commit 90883a4d25b0c73be9962b04f033dfa5e1705db4 Author: Zhongwei Li Date: Sun Nov 30 08:35:59 2025 +0800 Initial commit diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..a37c450 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,21 @@ +{ + "name": "geoffrey", + "description": "Personal AI infrastructure with learning-enabled assistance for work, travel, and personal tasks", + "version": "0.1.0", + "author": { + "name": "Kris Hagel", + "email": "kris@krishagel.com" + }, + "skills": [ + "./skills" + ], + "agents": [ + "./agents" + ], + "commands": [ + "./commands" + ], + "hooks": [ + "./hooks" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c33f3a6 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# geoffrey + +Personal AI infrastructure with learning-enabled assistance for work, travel, and personal tasks diff --git a/agents/.keep b/agents/.keep new file mode 100644 index 0000000..e69de29 diff --git a/commands/preferences.md b/commands/preferences.md new file mode 100644 index 0000000..28bf5bd --- /dev/null +++ b/commands/preferences.md @@ -0,0 +1,153 @@ +--- +description: View and manage your learned preferences and knowledge +--- + +# Preferences Command + +Read and display all stored preferences from Geoffrey's knowledge base. + +## What This Command Does + +The `/preferences` command shows you everything Geoffrey has learned about you, including: +- All stored preferences organized by category +- Confidence scores for each preference +- When each preference was learned +- How each preference was learned (explicit, pattern, conversation) + +## Location + +Preferences are stored in: +``` +~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/knowledge/preferences.json +``` + +## How to Use + +### View all preferences: +``` +/preferences +``` + +Shows all preferences across all categories with confidence scores. + +### View by category: +``` +/preferences travel +/preferences work +/preferences communication +``` + +Shows only preferences in the specified category. + +## What You'll See + +``` +Geoffrey's Knowledge Base +Last updated: 2025-11-17 10:30 AM + +Travel Preferences: + Hotels: + - Primary chain: Marriott + - Loyalty tier: Platinum Elite + - Room preferences: High floor, away from elevator + - Confidence: 1.0 (explicitly stated) + - Learned from: explicit:2025-11-17 + + Airlines: + - Primary: Alaska Airlines + - Seat preference: Aisle + - Time preference: Morning flights + - Confidence: 0.8 (strong pattern) + - Learned from: booking:2025-10-15, booking:2025-09-20 + +Work Preferences: + Communication: + - Email tone: Professional but friendly + - Confidence: 0.6 (moderate pattern) + - Learned from: conversation:2025-11-10 + +Total preferences: 8 +High confidence (>0.8): 5 +Moderate confidence (0.6-0.8): 2 +Low confidence (<0.6): 1 +``` + +## Actions You Can Take + +After viewing preferences, you can: + +1. **Teach Geoffrey something new**: + ``` + "I prefer window seats on flights, not aisle" + ``` + +2. **Update existing preferences**: + ``` + "Actually, I prefer Hilton over Marriott now" + ``` + +3. **Delete preferences**: + ``` + "Forget my airline preferences" + ``` + +4. **Ask questions**: + ``` + "Why do you think I prefer morning flights?" + "How confident are you about my hotel preferences?" + ``` + +## File Format + +The preferences.json file has this structure: +```json +{ + "version": "1.0", + "last_updated": "2025-11-17T10:30:00Z", + "preferences": { + "travel": { + "hotels": { + "primary_chain": "Marriott", + "loyalty_tier": "Platinum Elite", + "room_preferences": ["high floor", "away from elevator"], + "confidence": 1.0, + "learned_from": ["explicit:2025-11-17"], + "last_updated": "2025-11-17T10:30:00Z" + } + } + } +} +``` + +## Privacy & Security + +- **Local storage only**: Preferences stored in your iCloud, not on any server +- **Syncs across your devices**: Via iCloud Drive +- **You control the data**: Edit or delete the JSON file directly if needed +- **No analytics**: Geoffrey never sends your preferences anywhere + +## Troubleshooting + +**If /preferences shows nothing:** +- Check if the knowledge file exists +- Initialize with: `mkdir -p ~/Library/Mobile\ Documents/com~apple~CloudDocs/Geoffrey/knowledge` +- Teach Geoffrey something to create initial file + +**If file is corrupted:** +- Backup: `cp preferences.json preferences.backup.json` +- Fix JSON formatting or reset to empty: `{}` + +**If preferences not syncing:** +- Verify iCloud Drive is enabled +- Check iCloud storage space +- Wait a few minutes for sync + +## Implementation Notes + +This command should: +1. Read the preferences.json file +2. Parse and format for display +3. Show confidence scores with visual indicators +4. Group by category +5. Provide summary statistics +6. Offer next action suggestions diff --git a/hooks/hooks.json b/hooks/hooks.json new file mode 100644 index 0000000..e641edb --- /dev/null +++ b/hooks/hooks.json @@ -0,0 +1,21 @@ +{ + "comment": "Geoffrey hooks configuration - Phase 1 placeholder", + "hooks": { + "post-conversation": { + "description": "Extract learnings after each conversation (Phase 4)", + "enabled": false, + "script": null + }, + "pre-command": { + "description": "Prepare context before command execution (future)", + "enabled": false, + "script": null + }, + "session-start": { + "description": "Initialize Geoffrey on session start (future)", + "enabled": false, + "script": null + } + }, + "version": "0.1.0" +} diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..3b35edd --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,1177 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:krishagel/geoffrey:", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "dd7704b9e19f046a16f0ff9a088a8b29821141ee", + "treeHash": "64ed8ff88264cec7703698104d9fdd868330a37557d0a947a3e9ab5c2303e116", + "generatedAt": "2025-11-28T10:19:58.995038Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "geoffrey", + "description": "Personal AI infrastructure with learning-enabled assistance for work, travel, and personal tasks", + "version": "0.1.0" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "125e3ed4a0112feb0e47b2445e4bcb1f9e9ca2dfdb0bce91d7ddc815601af02f" + }, + { + "path": "agents/.keep", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "hooks/hooks.json", + "sha256": "8b3d11e90f22d7890491e889b574babaa5d1462b89566006fea1f9f6d1af4b80" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "4984bb01d69ae00c33c038d772f3086cd71d2ba2220acf4e79a67885754eadfd" + }, + { + "path": "commands/preferences.md", + "sha256": "a4d0e3094d817e98e4a36f10795ca3b2989fe65335e11481fd8085f656290db5" + }, + { + "path": "skills/research/SKILL.md", + "sha256": "6419fbbeabcc43d6b20c2c4aaf1e70159dbacfcc0dffd5b34f4c383310fa006d" + }, + { + "path": "skills/research/RESEARCH_ENHANCEMENT.md", + "sha256": "8cc7fdd730a6d0013d5b140f4b488172086b644cc79a21b6f504d770cfaeb939" + }, + { + "path": "skills/research/agents/claude-researcher.md", + "sha256": "d31f8ad42fd08aebe30b686f4aa01b04df6980ed239f61acaea56696e77f69f7" + }, + { + "path": "skills/research/agents/gemini-researcher.md", + "sha256": "f11ecc56b29dc57ad5f6f6086625b07c016f602567025af823825a0b663652e4" + }, + { + "path": "skills/research/agents/openai-researcher.md", + "sha256": "b795578ead27dd6f1a1b94af074c11b9e0c81643c34fdd025f006adf4cf17b21" + }, + { + "path": "skills/research/agents/perplexity-researcher.md", + "sha256": "50b2a2d4d35f5c0188e51c38d17cc4f7b01c8dea595a5201bcc25711f62cbc79" + }, + { + "path": "skills/research/scripts/context-loader.js", + "sha256": "da8b53e95311cf7f0b9502053197b5adb57cbb56487f536e70e866053147c27f" + }, + { + "path": "skills/research/scripts/orchestrator.js", + "sha256": "61c19831af450e4bd3e290ae3dd9df1a63f6a8ee6671b7e4ac382ecfb0156a21" + }, + { + "path": "skills/research/commands/conduct-research.md", + "sha256": "4f45eb3bf312b51ac9af8b009d62ecd9f8f947513bf3ff39c12066e45b27b996" + }, + { + "path": "skills/image-gen/SKILL.md", + "sha256": "9ae14ace3e4dc493275ccb0c905a4d0eee9dd1acb9712d747381986a11b51b5c" + }, + { + "path": "skills/image-gen/workflows/infographic.md", + "sha256": "4614bba1ecc0a9095c5cc584a7dee8aa0ea07fa5c1f121e7913369b686d788a5" + }, + { + "path": "skills/image-gen/workflows/diagram.md", + "sha256": "4c3b724a8a03824cf3383087a5102e850c818f352063219dadf857d928a2d5a6" + }, + { + "path": "skills/image-gen/scripts/compose.py", + "sha256": "79183749032c9a49e304692bbd3cebc300b325086e0ffe7a303a45aad7dea420" + }, + { + "path": "skills/image-gen/scripts/generate.py", + "sha256": "308a4c7601588f6fd11a20408c04ab5456cac2dca1afa3e356d453798c7e9450" + }, + { + "path": "skills/image-gen/scripts/edit.py", + "sha256": "70205c2ce4ffcb2310b28c5d8d18110d9743f86537aa76e769de6113751e41d0" + }, + { + "path": "skills/knowledge-manager/SKILL.md", + "sha256": "4d5df4f1eacb93a6e104b64c77a01ad6798858799062acd4a15f997e59205c25" + }, + { + "path": "skills/omnifocus-manager/SKILL.md", + "sha256": "7786fc56201136aefb31faaa6f2ab88bc13b07c1b26f57292e31cefa81be63be" + }, + { + "path": "skills/omnifocus-manager/scripts/create_tag.js", + "sha256": "0672901c5d52768cdcb0c9a51100d3df346c0662f111276b47be6b4e3907ee62" + }, + { + "path": "skills/omnifocus-manager/scripts/get_projects.js", + "sha256": "49da32954d1b50d17406aec277f3ece4c19043e6638b3035feb801e9bf1fb1cf" + }, + { + "path": "skills/omnifocus-manager/scripts/add_task.js", + "sha256": "f20da6449e5ccaabafb87f3c033a7c862b27257c14f65692b90d47bf23fc4cb3" + }, + { + "path": "skills/omnifocus-manager/scripts/update_task.js", + "sha256": "fddb37e48f598f5af0f82fc9f56ff46fb5179bf824194fad6ef3c201c2db61db" + }, + { + "path": "skills/omnifocus-manager/scripts/get_inbox.js", + "sha256": "20a4115b40cfaf052b558fd29ef405a4fc2b2d2261f0908590eff3344d233ca5" + }, + { + "path": "skills/omnifocus-manager/scripts/get_tags.js", + "sha256": "98a8fe924564745e90b153d5314fbaf7bb251af2103ba5a4ae30553e146fe561" + }, + { + "path": "skills/drafts-manager/SKILL.md", + "sha256": "36b915ddac86830aeab0179b8f4de0ede368c7eee279d4d4cc43dfe18960893c" + }, + { + "path": "skills/drafts-manager/scripts/trigger_export.js", + "sha256": "a7668ee433e06593635737c0d599c2611e13e4d293a84e9d40c3dd27f72d0f4a" + }, + { + "path": "skills/drafts-manager/scripts/add_contact.js", + "sha256": "77ccab653d1f4ffed9366d39cc118f4445abae640eb7a5010d11ae3fe5805cec" + }, + { + "path": "skills/drafts-manager/scripts/trigger_process.js", + "sha256": "9df07b644075135115d01ac74ff82144e3d48a3e69e6b062dc04684b2a3a3f35" + }, + { + "path": "skills/drafts-manager/actions/geoffrey-process-draft.js", + "sha256": "a540802be6ec808e08770b9e2b1f13c6f2b5396b123e9ede123997fea11d1029" + }, + { + "path": "skills/drafts-manager/actions/README.md", + "sha256": "812a1a8236709d7bf55e9160e9992c78497ba39040f0ded9af173a164e0ed037" + }, + { + "path": "skills/drafts-manager/actions/geoffrey-export-inbox.js", + "sha256": "8e51e8af315b98c366404a79147941ef81005601c67f7a18bdbf3b1c7b0f73f5" + }, + { + "path": "skills/xlsx/recalc.py", + "sha256": "ab1ef0c94536bb23b6c6a3d32769b0401ec3cc85e73c247d574dd84ec73af15d" + }, + { + "path": "skills/xlsx/SKILL.md", + "sha256": "b34935a63278788ee2c8def0345979d90cc98e5c69e51b002f11a4fdc9331647" + }, + { + "path": "skills/xlsx/LICENSE.txt", + "sha256": "79f6d8f5b427252fa3b1c11ecdbdb6bf610b944f7530b4de78f770f38741cfaa" + }, + { + "path": "skills/pdf/reference.md", + "sha256": "03a5f964f8abecbbe156f363356e927e864d7ee964f1012c84ee1bfc8acbeb95" + }, + { + "path": "skills/pdf/forms.md", + "sha256": "0ab10e9095deb1c1f9f79eb04254589f55c1d16e095cb53191e03f9fc3184449" + }, + { + "path": "skills/pdf/SKILL.md", + "sha256": "43b44a41270f7a0b285a4f15937e0609422f1f36f18ee5303a528defb0f81053" + }, + { + "path": "skills/pdf/LICENSE.txt", + "sha256": "79f6d8f5b427252fa3b1c11ecdbdb6bf610b944f7530b4de78f770f38741cfaa" + }, + { + "path": "skills/pdf/scripts/fill_fillable_fields.py", + "sha256": "65b3e41969707022283a313a4cf9696d31793cbe255dffe13370e75abda448a7" + }, + { + "path": "skills/pdf/scripts/convert_pdf_to_images.py", + "sha256": "095a0105a718af75ede309cb03f84a20c81d17f1727f7686fd4b294f1f40294f" + }, + { + "path": "skills/pdf/scripts/extract_form_field_info.py", + "sha256": "9db1a2720cf54223cdc4bf797080c70f4e0d27288d9f400e066c14524519021d" + }, + { + "path": "skills/pdf/scripts/check_bounding_boxes.py", + "sha256": "eb2a5f79c8aa10c57b5867e1f0fc75b52a68b1218442ef9d838dfb4b9eedc6f4" + }, + { + "path": "skills/pdf/scripts/check_bounding_boxes_test.py", + "sha256": "f95dca01a8b79aafd152511e9f7bf2bbcd606dde1be77d691f03a18624e002ca" + }, + { + "path": "skills/pdf/scripts/create_validation_image.py", + "sha256": "89675be66b48925d7b498eb9454521c78cf9e9ff188ebf094934b598550effe5" + }, + { + "path": "skills/pdf/scripts/fill_pdf_form_with_annotations.py", + "sha256": "599d6f307edb4ee6b837f21d0ea860c41c22246e270b45d6bc750c5b87c86ce0" + }, + { + "path": "skills/pdf/scripts/check_fillable_fields.py", + "sha256": "250d5aa4e8451d6a83d17d3550c14e6c844ac347145f916ebf7980b118312b41" + }, + { + "path": "skills/presentation-master/README.md", + "sha256": "9da402d69fd662857c6e5fb35022cbbd6618e36ee27613c4384ebf5d221732c5" + }, + { + "path": "skills/presentation-master/package.json", + "sha256": "01067f03eed347bee5317777c2d07ccce3150f0e1e972b0c214abe13f718a704" + }, + { + "path": "skills/presentation-master/SKILL.md", + "sha256": "ba745c650d8c27164e5cd9559d051a6485364f650acc99a555e61f43f845cbc4" + }, + { + "path": "skills/presentation-master/adapters/pptx-adapter.js", + "sha256": "f4ae0aa2b648a8c23de000ed84870acf03a63472e7bec047132ee509e4e29f25" + }, + { + "path": "skills/presentation-master/adapters/slides-adapter.js", + "sha256": "4649e12069a0a112e63c378d48caec7d4a168efb180e1457ac3e990fa79f3d7c" + }, + { + "path": "skills/presentation-master/scripts/suggest-images.js", + "sha256": "73daabde492982f41a538fa35eb27877a46a627da9730d7580391c10a9a10a6b" + }, + { + "path": "skills/presentation-master/scripts/validate-presentation.js", + "sha256": "e57a6a0b3193fdd4f6ddc6216bfa6221979e2d9b7927c20b8826d72ec4ed9c4c" + }, + { + "path": "skills/presentation-master/scripts/analyze-context.js", + "sha256": "51ab66b743be3768345e5541a8ec3d30f4296eddee7daa35c6b530f834dd15bb" + }, + { + "path": "skills/presentation-master/principles/validation-rules.md", + "sha256": "b520759f8dbe80ab4b40dd1f882e9409c97c1d74d3c353d0aa6bed96dab9fa08" + }, + { + "path": "skills/presentation-master/principles/story-frameworks.md", + "sha256": "7c6a1c48cf626cbb61937ab14397e1af80fdf0cde07542f974c53822d9bbbc1f" + }, + { + "path": "skills/presentation-master/principles/slide-patterns.md", + "sha256": "13ecf6c5f02f93e710fbe1932c4231edec68696ee5824e20fc90cf9183ee5221" + }, + { + "path": "skills/presentation-master/principles/masters.md", + "sha256": "3edf73d3d5dbd2d0cfff5f7da0fb1aa51c3ab8a1aa927d3acdb52bb949cccd7c" + }, + { + "path": "skills/skill-creator/SKILL.md", + "sha256": "bd1c12d147b34e9a70fadff1d6bdcaa6a446d13c32916f7533cf765eec0138d3" + }, + { + "path": "skills/skill-creator/LICENSE.txt", + "sha256": "58d1e17ffe5109a7ae296caafcadfdbe6a7d176f0bc4ab01e12a689b0499d8bd" + }, + { + "path": "skills/skill-creator/references/workflows.md", + "sha256": "ef4846877d5dab47511a01a6cf31476ad64f5bc5945635459295794575338980" + }, + { + "path": "skills/skill-creator/references/output-patterns.md", + "sha256": "d6027800b9d8c26589edba85b42901a41ac36d753b4e9cebc7f4cbb03cdcf0a4" + }, + { + "path": "skills/skill-creator/scripts/init_skill.py", + "sha256": "0bba250b94caa4cb2b28b15dad26fdcf371aeda4c9797b8120e55c2e33e0c73c" + }, + { + "path": "skills/skill-creator/scripts/package_skill.py", + "sha256": "b31fbcb3e362d5c5308e99255ff8e83cde3a513e0636953964a648494ca10931" + }, + { + "path": "skills/skill-creator/scripts/quick_validate.py", + "sha256": "381ab2d3d1fd5ec32371016413063eff99d0d48c415747085c61517e967dbb87" + }, + { + "path": "skills/pptx/ooxml.md", + "sha256": "09868e9f1786765421ecf3f0f49c77006738efda82a76df43ed87f7a9bfe2467" + }, + { + "path": "skills/pptx/SKILL.md", + "sha256": "59cf57c93c43f30490463801375088c138429f26b3b50b2d9231c97d28787c2a" + }, + { + "path": "skills/pptx/html2pptx.md", + "sha256": "f08ed7580969b796d9cd5ade93e2cdee981dcaf13cc5eb12e8d4a3700c2d6047" + }, + { + "path": "skills/pptx/LICENSE.txt", + "sha256": "79f6d8f5b427252fa3b1c11ecdbdb6bf610b944f7530b4de78f770f38741cfaa" + }, + { + "path": "skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd", + "sha256": "842e7163409c8d74f4d7088a8bc99500d80bc75332681a0980055b08f374a604" + }, + { + "path": "skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd", + "sha256": "0fa75578a000439a7988ba0c59fdc69f774bbd416cbacc14d07125b3f686cb74" + }, + { + "path": "skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd", + "sha256": "568b26ee156cb9549aa439ca2158965f77b7c1602b7e0316f40ac6cf586e35f2" + }, + { + "path": "skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd", + "sha256": "127ca209fa73d7cb708449cb355c871867948a96e4a74f7bf5811ef62d17991d" + }, + { + "path": "skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd", + "sha256": "16f6f8072249f431370723c2cd8974672e0d9c897e00e97dd918079df934871b" + }, + { + "path": "skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd", + "sha256": "fddc2b880cabb9005aebbc7e783e53c19fec1c03df7d0e2f2076a33a0fdfd081" + }, + { + "path": "skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd", + "sha256": "be0ff793a22dd31384650c3a4da14c2fa8062751c2e97b0e5ee852bda13c60ad" + }, + { + "path": "skills/pptx/ooxml/schemas/mce/mc.xsd", + "sha256": "3a37e461ecf5a8670fdec34029703401f8728ab9c96ec1739a6ae58d55212413" + }, + { + "path": "skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd", + "sha256": "451958454e8588dfc7cd945981ada142ca06ff3307937f5700df059c2b307fa8" + }, + { + "path": "skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd", + "sha256": "f565adfef5a502044abc3a9153e157edc25af78304d335994afb958874b15e26" + }, + { + "path": "skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd", + "sha256": "9e0b7209fc69ab11987900404540969976000c5ebe4d4f58c43dc3842886bf3a" + }, + { + "path": "skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd", + "sha256": "6de111e11403f7cd49027400755bae0ea1cabef2815f09bd40a24f0017613b24" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd", + "sha256": "133c9f64a5c5d573b78d0a474122b22506d8eadb5e063f67cdbbb8fa2f161d0e" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd", + "sha256": "585bedc1313b40888dcc544cb74cd939a105ee674f3b1d3aa1cc6d34f70ff155" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd", + "sha256": "0d103b99a4a8652f8871552a69d42d2a3760ac6a5e3ef02d979c4273257ff6a4" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd", + "sha256": "d173c3e5d61e42e2e3a97226c632fd2ab7cc481fc4e492365b87024ab546daff" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd", + "sha256": "5cb76dabd8b97d1e9308a1700b90c20139be4d50792d21a7f09789f5cccd6026" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd", + "sha256": "41b93bd8857cc68b1e43be2806a872d736a9bdd6566900062d8fdb57d7bbb354" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd", + "sha256": "3fd0586f2637b98bb9886f0e0b67d89e1cc987c2d158cc7deb5f5b9890ced412" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd", + "sha256": "beffeed56945c22a77440122c8bdc426f3fcbe7f3b12ea0976c770d1f8d54578" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd", + "sha256": "6bdeb169c3717eb01108853bd9fc5a3750fb1fa5b82abbdd854d49855a40f519" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd", + "sha256": "c2dd9f61f892deae6acd8d20771ea79b12018af25f3bf8d06639c8542d218cfd" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd", + "sha256": "5d389d42befbebd91945d620242347caecd3367f9a3a7cf8d97949507ae1f53c" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd", + "sha256": "29b254ee0d10414a8504b5a08149c7baec35a60d5ff607d6b3f492aa36815f40" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd", + "sha256": "5375417f0f5394b8dd1a7035b9679151f19a6b65df309dec10cfb4a420cb00e9" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd", + "sha256": "9c085407751b9061c1f996f6c39ce58451be22a8d334f09175f0e89e42736285" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd", + "sha256": "b4532b6d258832953fbb3ee4c711f4fe25d3faf46a10644b2505f17010d01e88" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd", + "sha256": "e2abacbb9a55ce1365f8961bc1b1395bbc811e512b111000d8c333f98458dece" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd", + "sha256": "bdad416b096b61d37b71603b2c949484f9070c830bdaeba93bf35e15c8900614" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd", + "sha256": "475dcae1e7d1ea46232db6f8481040c15e53a52a3c256831d3df204212b0e831" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd", + "sha256": "0b364451dc36a48dd6dae0f3b6ada05fd9b71e5208211f8ee5537d7e51a587e2" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd", + "sha256": "bc92e36ccd233722d4c5869bec71ddc7b12e2df56059942cce5a39065cc9c368" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd", + "sha256": "f5ee623b08b6a66935e5aced2f5d8ad0fc71bf9e8e833cd490150c0fa94b8763" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd", + "sha256": "a539aa2fb154fa50e0f5cc97e6ad7cbc66f8ec3e3746f61ec6a8b0d5d15ecdf2" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd", + "sha256": "12264f3c03d738311cd9237d212f1c07479e70f0cbe1ae725d29b36539aef637" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd", + "sha256": "0ef4bb354ff44b923564c4ddbdda5987919d220225129ec94614a618ceafc281" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd", + "sha256": "7b5b7413e2c895b1e148e82e292a117d53c7ec65b0696c992edca57b61b4a74b" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd", + "sha256": "3213ef1631606250f5010b42cad7ef716f7c59426367798e33c374c0ec391d3a" + }, + { + "path": "skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd", + "sha256": "3c6709101c6aaa82888df5d8795c33f9e857196790eb320d9194e64be2b6bdd8" + }, + { + "path": "skills/pptx/ooxml/scripts/pack.py", + "sha256": "6fe762f45aff8c63fd95b9fcb1337b28921d6fa454e18a0e8158d4c8708d6d00" + }, + { + "path": "skills/pptx/ooxml/scripts/validate.py", + "sha256": "1ec252de8b14b07d16966c48906ccb1c45c68bcd23557ad31d8c50a27f5f8c0f" + }, + { + "path": "skills/pptx/ooxml/scripts/unpack.py", + "sha256": "0bd17f76a1a4c388aba42c6d1d39015fa84e405c3e0692397fe12762bd632b58" + }, + { + "path": "skills/pptx/ooxml/scripts/validation/docx.py", + "sha256": "e65d6cda0525866a24cc847b2e883bd2416ae6f87b3f5b9e2784dfbb0ec13093" + }, + { + "path": "skills/pptx/ooxml/scripts/validation/__init__.py", + "sha256": "83e0f035c5abea238d3f2c3968afbd511ed022b527b7c9cb60a9434cc34ff987" + }, + { + "path": "skills/pptx/ooxml/scripts/validation/redlining.py", + "sha256": "97abfdff4f08f43f9a4bb5c8a2f8fd483398b5b339592724e8635153b5507967" + }, + { + "path": "skills/pptx/ooxml/scripts/validation/pptx.py", + "sha256": "00bf2623da1177b3948143a4ade2f1cda7cb389dee31960861913fa42ef1b00f" + }, + { + "path": "skills/pptx/ooxml/scripts/validation/base.py", + "sha256": "f2c70d481613456e32b43869d1604b05c236c8da34b5b3967677a661cac7ba63" + }, + { + "path": "skills/pptx/scripts/html2pptx.js", + "sha256": "c675d09a54d6a002e8ca5917b9d24a6568aa8d455bb7abeb212d4f564dd07a34" + }, + { + "path": "skills/pptx/scripts/thumbnail.py", + "sha256": "c21fd950b6ada7bd2f029885d3e56bc66b7ff061cc8404c492eb301664aa9e5d" + }, + { + "path": "skills/pptx/scripts/rearrange.py", + "sha256": "c04ac37916f398ba621b2d9e1e4c1a69225eaad6d7fb0ad116c237ddeb1b2b68" + }, + { + "path": "skills/pptx/scripts/inventory.py", + "sha256": "adead8fe6270e520c397cec9fbee4d606ab10bb80f749e018b42ec894c60d2e5" + }, + { + "path": "skills/pptx/scripts/replace.py", + "sha256": "8a590747551be847a904e3296fb2f35aa4e7feeb4970a61596c2375306462820" + }, + { + "path": "skills/psd-brand-guidelines/SKILL.md", + "sha256": "5d5bb4e8569dfcd4ba3029c0316108f7455027ddc018ae0c9e833e81f8ef415e" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-white-horizontal.eps", + "sha256": "1496ff125fa471ec70b360d95877693f656c8238bf5e967eac9e6c15d0f85602" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-green-fulllandscape.eps", + "sha256": "aabbf0ad4a51c0fca84eab09e6fd6815c74e2d292156eb5d6c2bda45c567900a" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-2color-square.png", + "sha256": "e8f288174781225944d960108a10ff41fa31532fabbd0ae3b3c045d99700caa9" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-2color-horizontal.eps", + "sha256": "c4fc3e03d6799972fbde74aeb92ab3f1adcf54afe2b375c8d62ff4173ff967a4" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-blue-square.png", + "sha256": "3c2fc49ba0a20be5e57a871cdad4935c19b257127ff30aacbd8d7e6f69443ec7" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-green-horizontal.eps", + "sha256": "aa3da603a68b9374b48fef642d17bf287dbb44d1ffb5522bf217d0d034742f9c" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-green-square.eps", + "sha256": "b0f43f7c69cacf3acd1f7229487e742188097c07c060db50aafd347e53540897" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-white-square.png", + "sha256": "108101163ec9287893baa8c1aa6796e0b37af04110442bde8f8014da8c93cad1" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-2color-fulllandscape.eps", + "sha256": "c1d6f69f575b394e8962e4b9b109228a78dcb715592f65a4480462f4ee76bbde" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-blue-fulllandscape.png", + "sha256": "d64ae6dfd5bc839f56586a2207a0e6ea6c501a40e58320cf31ad6a23b635d1bb" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-2color-stacked.png", + "sha256": "c9b90d95ca1513feda4afd806013d2c37866682e86b0d592e6d448b53949f560" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-white-stacked.eps", + "sha256": "212edd0ef5b03fcdc1e0b6f738e218129e6844cbf0cbf65b3273f08a7600198e" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-blue-stacked.png", + "sha256": "4f9bbb3d2c29145b8f3e3c17911c100ef477f2afdd420b2623bdd9bcb2bff165" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-2color-emblem.eps", + "sha256": "b66f54bc1c60fcca53c2b826f82237893a88dc8715bde148623cdd2c652d483b" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-blue-emblem.eps", + "sha256": "78a97b0b06494f5a4ccaef152823f517f8c66d285ce738b77fe38a91215378f4" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-green-emblem.png", + "sha256": "decdaba724a57124fd9b5d4ee53331c781e254975de3f59f9594bcbf384ccfa9" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-white-emblem.eps", + "sha256": "3d67fc0fa698f787f3a5bf74a458ef34ad588590d503a59e02c9c867a0f1c08a" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-green-stacked.png", + "sha256": "96d54699fa41d1265a7037dc73f93ad8090e508135f42529b71a48ab145337b3" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-blue-horizontal.eps", + "sha256": "1141ef9cc5d699e12c755a5c4044bab03234b506f4f70f3e8f60d75ad3807272" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-white-stacked.png", + "sha256": "d9477c70a2989275ec4e668a768d0db6802254e912b3d42723d8beac3c4f402f" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-2color-stacked.eps", + "sha256": "bdb7a4354349dcdbcb5e1c38a49842d47ccc17e3d95b9a41bd5a793bde581dfb" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-blue-stacked.eps", + "sha256": "5e4d242d4bcc1a4d12f9fc304ec866326965437223d3d5f950ccefe96ec58fa0" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-green-emblem.eps", + "sha256": "4d47a8b762b3e7b516a517cfb2e9c648ec04e0faac0c858414b0ab7299eaf976" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-white-emblem.png", + "sha256": "370d62b875b77ff88bbb75746af8aeb6672cf275f25b12555c501cdb4fbd9ac8" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-blue-emblem.png", + "sha256": "e91d338d9fcdc56e300c7388bb7464ce2a9ee0efca71965548bfc1c79f1c261c" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-2color-emblem.png", + "sha256": "c91f24bc1c69d6bcadb670c5bb48660ad9007cd1076e41e1a89ac3e5852f1840" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-green-stacked.eps", + "sha256": "a022e34b1a1c931ab48749316b7958c13b06c253b8bccfe0d8ba28f7a4b2cb52" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-blue-horizontal.png", + "sha256": "e0fe33b60c7062ab0905cff9225ff930246fd9812b1a4a81391611e237ec6934" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-green-fulllandscape.png", + "sha256": "f82a4c76ec749eb3033bc09577e3f5a29dd9a7e8bf93625a4c624eee92f47f89" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-white-horizontal.png", + "sha256": "7db6ad5cc69dacb39531be2a1bb35a9cdd6f9f6f1360c971ab9612efe4df1a15" + }, + { + "path": "skills/psd-brand-guidelines/assets/PSD_Branding_Guide.pdf", + "sha256": "fe27d19a074ce853a46591e237c70b09c1e67405e5d1c4b84b9bd1b0ba9f0adf" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-green-square.png", + "sha256": "8862951cee24659d389beece13c9bfae90c7adbc6aee2c8077565d5b307ab55a" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-white-square.eps", + "sha256": "763f229c27e39a447dc2c1421442accca0089a9fb7dbdf2e2322d8032298d731" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-green-horizontal.png", + "sha256": "7002421189331d0d1c8b0aa48d2020c47f51e95691690fc2e4f559d4983686d2" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-blue-square.eps", + "sha256": "eecec432ce46bfe5f865c7554d4b834e18e2c30f07edb08145d3c98fc99c092a" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-2color-square.eps", + "sha256": "e014dbe750c685a266d3ebf69f9471f22e9e80bfeb546aa24bae39b443b14d59" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-2color-horizontal.png", + "sha256": "b27c4a624559f1fbb5f1e1298cf3f5d58e6daae917b1d77014a2710ab3b13fc2" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-2color-fulllandscape.png", + "sha256": "81bcaed08a9d4288f190ccb13a5ea26d2bb63ab1b7576db16c531a2fe14276df" + }, + { + "path": "skills/psd-brand-guidelines/assets/psd_logo-1color-blue-fulllandscape.eps", + "sha256": "2e98e4ff14afba3117d3e4ed5f372f38f23035881f72ce1e464be1224774c1b5" + }, + { + "path": "skills/google-workspace/bun.lock", + "sha256": "c23be0399863b68070ff3130725d79c36e269030cfc1404e5f2cb9b7ba0a57d1" + }, + { + "path": "skills/google-workspace/package.json", + "sha256": "dd3cc90a6bf38c28823784cdef581aad3394afc8710e825e7aa8125e1eee9c93" + }, + { + "path": "skills/google-workspace/SKILL.md", + "sha256": "94d2aca89d008d1f713e1f47bedbc0e4f6d43534ec154ae9ff9705d3603cd926" + }, + { + "path": "skills/google-workspace/calendar/create_event.js", + "sha256": "43a3be1aaad420726511d0596330e255757ca2c30035be6e466b2dc123a57f3f" + }, + { + "path": "skills/google-workspace/calendar/update_event.js", + "sha256": "bb0a6d2093a5af9b437775bc52be8e6ea7d06bcd70c6819bbc5ae3cc3c618e67" + }, + { + "path": "skills/google-workspace/calendar/list_events.js", + "sha256": "d56ba9b113c6fde4758e99755d2ea96a964a8e8a508454d013b56873306b5423" + }, + { + "path": "skills/google-workspace/calendar/search_events.js", + "sha256": "d5dfed21754ac7446270bf6d6b9d06bf7fb3ab81fe51e5e850b78e095a6d0752" + }, + { + "path": "skills/google-workspace/sheets/read_sheet.js", + "sha256": "15bf28bc29b2607d77238ef568db932bb5e330b5edaea46d88ad96d02279e2ad" + }, + { + "path": "skills/google-workspace/sheets/edit_sheet.js", + "sha256": "ca8e742a4538d884359114f0a2ca850ef9234f2198ef986895347b1c84305e8e" + }, + { + "path": "skills/google-workspace/sheets/create_sheet.js", + "sha256": "afe037dafda6b7d02a9d3b0943c590e1e23a33aeb28f07653e8886adc72d716c" + }, + { + "path": "skills/google-workspace/chat/send_message.js", + "sha256": "a14922e07fab511b1d5dc03d06bb8ada6bdc80aeae753589346b0f4f6f409561" + }, + { + "path": "skills/google-workspace/chat/list_spaces.js", + "sha256": "c47aa91f27b4d540f1a1a49355d85c29faf64f7fcb856689b93c308b82c676a1" + }, + { + "path": "skills/google-workspace/chat/read_messages.js", + "sha256": "2b53b864c53dc1984a61fddd04f37df284f382ab80aa2293c7d637a9e736d0cb" + }, + { + "path": "skills/google-workspace/auth/token_manager.js", + "sha256": "cafa11641ea5a5bed6d98170cecc101a379eb9f8a4fac94bb3025ed3989667ac" + }, + { + "path": "skills/google-workspace/auth/oauth_setup.js", + "sha256": "324004a7c16e63808f3abdaf1325e09133fb3da04b266a4749e06f14272262c5" + }, + { + "path": "skills/google-workspace/auth/GOOGLE_CLOUD_SETUP.md", + "sha256": "202088b59e6238415b0abb37fd051b7019a9357ecd7438b3c5f9ca24f147a8d6" + }, + { + "path": "skills/google-workspace/utils/markdown_to_docs.js", + "sha256": "2d030c6b2f0da5b19a1f0ce782530e31b909e3045734dd153fc7a512eb2b29e4" + }, + { + "path": "skills/google-workspace/utils/folder_manager.js", + "sha256": "fbc0c1970f1d7435051e5efec28d7911dc968d0df2e826abf6d88c7b7e3fd7fb" + }, + { + "path": "skills/google-workspace/docs/create_doc.js", + "sha256": "86dc3af89fdbe7c17621e70a8a71af656485c10e3949d5e801c51c5ceb4cd8a0" + }, + { + "path": "skills/google-workspace/docs/read_doc.js", + "sha256": "2cb345d2d9016aec16379a38c36de2718b0d542ab62a2bd0f884ffe71f5489f2" + }, + { + "path": "skills/google-workspace/docs/edit_doc.js", + "sha256": "d442da81d1dab156df002e09c73c5972a829102eea975db3be108c26c549fceb" + }, + { + "path": "skills/google-workspace/slides/read_presentation.js", + "sha256": "52006c217c95fc88bc9fd2c279345f5ff10dc6f47a94d60fe596a9731ce974e8" + }, + { + "path": "skills/google-workspace/slides/edit_presentation.js", + "sha256": "dc056595526003718a75bd13cd04de9fe6e0ec59639553ccc3ebe9bd418b45b9" + }, + { + "path": "skills/google-workspace/slides/create_presentation.js", + "sha256": "bd3695fc555b9842596169bcfe116751c91b91cd290c5a2319434afbc4283daf" + }, + { + "path": "skills/google-workspace/drive/list_files.js", + "sha256": "3c8d97a3c0e373a05d2df6954e06c529ff4723e093bdd9d0b0968d1b2131513f" + }, + { + "path": "skills/google-workspace/drive/read_file.js", + "sha256": "321cb56ff2f724bdff13aa8594ee376cb35d29d496fe14840e4c4229aea2e5d8" + }, + { + "path": "skills/google-workspace/drive/download_file.js", + "sha256": "004223b5dc9cc2e4cacbfb28ab55f08952b63e33b660de372295704d773047f2" + }, + { + "path": "skills/google-workspace/drive/create_file.js", + "sha256": "e019e2847ec9e5d87b230cdd12ef122c2d41b41181ec0e629d3b87d41885e718" + }, + { + "path": "skills/google-workspace/gmail/send_message.js", + "sha256": "a6a4b5e6270fd5e44485f90d7badbeea5ffda924120e2c9ba93b44c50b571171" + }, + { + "path": "skills/google-workspace/gmail/read_message.js", + "sha256": "7ed50495258350e262ebbea12f64970904d81c64e7243b9ce4fa9ef989b2866e" + }, + { + "path": "skills/google-workspace/gmail/list_messages.js", + "sha256": "e7c9b560aaf4475082e22d32e94f2a606123245cb83940756797e8bc53881242" + }, + { + "path": "skills/google-workspace/gmail/search_messages.js", + "sha256": "1ad0af7c4be0d1c506dd3a6e88eff88549956cc13e4117f0739821561390909f" + }, + { + "path": "skills/freshservice-manager/SKILL.md", + "sha256": "070f84090141b33229ecddec470e2c2c165d58c853804e01de5efa45582c79ba" + }, + { + "path": "skills/freshservice-manager/scripts/get_service_request.js", + "sha256": "aa469d3b0ec9f52b09b90e945598276fcfdcd5d5b357e62dddfb4fc7a7461c4a" + }, + { + "path": "skills/freshservice-manager/scripts/get_daily_summary.js", + "sha256": "07102c4cbd7aa7a6afbc7f33fb4f5444b7c2361ab890694addafa1965eb4e133" + }, + { + "path": "skills/freshservice-manager/scripts/list_tickets.js", + "sha256": "1de1112884d92cb9a513ce41a841ecf1b9a72c6e480f05fbcf37f107feb84a8b" + }, + { + "path": "skills/freshservice-manager/scripts/create_ticket.js", + "sha256": "d9e3c5e49128677e0de5336a152514afbc4c4d77e3c07c37c77834212b79c2d3" + }, + { + "path": "skills/freshservice-manager/scripts/get_approvals.js", + "sha256": "1c19afc91394e42489f3c5fab108bbfb0da86313cb19bf8db05969c12516b106" + }, + { + "path": "skills/freshservice-manager/scripts/list_agents.js", + "sha256": "77c407e53c11c038cab8f2bd6a09f462ae62def1b86e263d9912ca22da21023f" + }, + { + "path": "skills/freshservice-manager/scripts/get_weekly_summary.js", + "sha256": "f12d340754f76434cb1604419d6530f210522bba944edce5d49c645303e89077" + }, + { + "path": "skills/freshservice-manager/scripts/get_ticket.js", + "sha256": "611d4d672da88f70a9d063899eeae0cbda10aa8467cc14974fd43e21386ffcdb" + }, + { + "path": "skills/freshservice-manager/scripts/get_agent.js", + "sha256": "788e30239735876a395c17e17f2c62a139f084e0a2a526dce2bb4cc8ee9f5bf6" + }, + { + "path": "skills/freshservice-manager/scripts/get_workspaces.js", + "sha256": "e267744aa122ba4c626b665110fece84cfa866595e418c6b7527d7f2c92ce05a" + }, + { + "path": "skills/freshservice-manager/scripts/add_note.js", + "sha256": "7c776249c9e9bc0053e75c82309c00fe157d150b7d59ddf062226362be67ea1a" + }, + { + "path": "skills/freshservice-manager/scripts/update_ticket.js", + "sha256": "76592061f99bbf722f42b00657948a006dd17ca43028763fa06c7bdf9934fa1b" + }, + { + "path": "skills/freshservice-manager/scripts/search_tickets.js", + "sha256": "7dace289f660d4b074b19e7260a2aca1ae2ff0e79ecce34c989f12679260e088" + }, + { + "path": "skills/obsidian-manager/SKILL.md", + "sha256": "628b49f1b43c2be9267fc219487f5aa65674653864eb1ab402512a98d76c529c" + }, + { + "path": "skills/obsidian-manager/scripts/search-readwise.py", + "sha256": "cafbcd2a099e95520b7cd0d060bba3fe3757c66a6bee236b98ab508265c32246" + }, + { + "path": "skills/obsidian-manager/scripts/open-in-obsidian.py", + "sha256": "70e489cdbfd01ae6ac0ae6b51f3d3df468cca43125a82308357080b8b248077b" + }, + { + "path": "skills/obsidian-manager/scripts/create-note.py", + "sha256": "b26fb0a411427d904783841d5c5c4398cf634d5ed0a7ee2f194fd78924de1c29" + }, + { + "path": "skills/obsidian-manager/scripts/search.py", + "sha256": "f0badff8e41cdcb7f36871168e8d284a254c3e76a1ae700bcbd7707383c2c103" + }, + { + "path": "skills/obsidian-manager/scripts/search-snipd.py", + "sha256": "9b21f2a8a1a4e1ce98eb726897a120b3ea1488d6d3efc9a1e877dfb4530d49bf" + }, + { + "path": "skills/docx/ooxml.md", + "sha256": "a16f922797eeaa3670ea31c1e49d15b799613d03f39445c857a5dd3221aa3597" + }, + { + "path": "skills/docx/docx-js.md", + "sha256": "83b4a2f88d058a10509fbc0b3b12b6933c407805f4d4afc955cd3fb939c16428" + }, + { + "path": "skills/docx/SKILL.md", + "sha256": "e7d650ce0c1ffd631ffaab07e43ba9502baf4a65ad0533c169ae40f84c713e43" + }, + { + "path": "skills/docx/LICENSE.txt", + "sha256": "79f6d8f5b427252fa3b1c11ecdbdb6bf610b944f7530b4de78f770f38741cfaa" + }, + { + "path": "skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd", + "sha256": "842e7163409c8d74f4d7088a8bc99500d80bc75332681a0980055b08f374a604" + }, + { + "path": "skills/docx/ooxml/schemas/microsoft/wml-2012.xsd", + "sha256": "0fa75578a000439a7988ba0c59fdc69f774bbd416cbacc14d07125b3f686cb74" + }, + { + "path": "skills/docx/ooxml/schemas/microsoft/wml-2010.xsd", + "sha256": "568b26ee156cb9549aa439ca2158965f77b7c1602b7e0316f40ac6cf586e35f2" + }, + { + "path": "skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd", + "sha256": "127ca209fa73d7cb708449cb355c871867948a96e4a74f7bf5811ef62d17991d" + }, + { + "path": "skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd", + "sha256": "16f6f8072249f431370723c2cd8974672e0d9c897e00e97dd918079df934871b" + }, + { + "path": "skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd", + "sha256": "fddc2b880cabb9005aebbc7e783e53c19fec1c03df7d0e2f2076a33a0fdfd081" + }, + { + "path": "skills/docx/ooxml/schemas/microsoft/wml-2018.xsd", + "sha256": "be0ff793a22dd31384650c3a4da14c2fa8062751c2e97b0e5ee852bda13c60ad" + }, + { + "path": "skills/docx/ooxml/schemas/mce/mc.xsd", + "sha256": "3a37e461ecf5a8670fdec34029703401f8728ab9c96ec1739a6ae58d55212413" + }, + { + "path": "skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd", + "sha256": "451958454e8588dfc7cd945981ada142ca06ff3307937f5700df059c2b307fa8" + }, + { + "path": "skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd", + "sha256": "f565adfef5a502044abc3a9153e157edc25af78304d335994afb958874b15e26" + }, + { + "path": "skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd", + "sha256": "9e0b7209fc69ab11987900404540969976000c5ebe4d4f58c43dc3842886bf3a" + }, + { + "path": "skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd", + "sha256": "6de111e11403f7cd49027400755bae0ea1cabef2815f09bd40a24f0017613b24" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd", + "sha256": "133c9f64a5c5d573b78d0a474122b22506d8eadb5e063f67cdbbb8fa2f161d0e" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd", + "sha256": "585bedc1313b40888dcc544cb74cd939a105ee674f3b1d3aa1cc6d34f70ff155" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd", + "sha256": "0d103b99a4a8652f8871552a69d42d2a3760ac6a5e3ef02d979c4273257ff6a4" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd", + "sha256": "d173c3e5d61e42e2e3a97226c632fd2ab7cc481fc4e492365b87024ab546daff" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd", + "sha256": "5cb76dabd8b97d1e9308a1700b90c20139be4d50792d21a7f09789f5cccd6026" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd", + "sha256": "41b93bd8857cc68b1e43be2806a872d736a9bdd6566900062d8fdb57d7bbb354" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd", + "sha256": "3fd0586f2637b98bb9886f0e0b67d89e1cc987c2d158cc7deb5f5b9890ced412" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd", + "sha256": "beffeed56945c22a77440122c8bdc426f3fcbe7f3b12ea0976c770d1f8d54578" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd", + "sha256": "6bdeb169c3717eb01108853bd9fc5a3750fb1fa5b82abbdd854d49855a40f519" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd", + "sha256": "c2dd9f61f892deae6acd8d20771ea79b12018af25f3bf8d06639c8542d218cfd" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd", + "sha256": "5d389d42befbebd91945d620242347caecd3367f9a3a7cf8d97949507ae1f53c" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd", + "sha256": "29b254ee0d10414a8504b5a08149c7baec35a60d5ff607d6b3f492aa36815f40" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd", + "sha256": "5375417f0f5394b8dd1a7035b9679151f19a6b65df309dec10cfb4a420cb00e9" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd", + "sha256": "9c085407751b9061c1f996f6c39ce58451be22a8d334f09175f0e89e42736285" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd", + "sha256": "b4532b6d258832953fbb3ee4c711f4fe25d3faf46a10644b2505f17010d01e88" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd", + "sha256": "e2abacbb9a55ce1365f8961bc1b1395bbc811e512b111000d8c333f98458dece" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd", + "sha256": "bdad416b096b61d37b71603b2c949484f9070c830bdaeba93bf35e15c8900614" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd", + "sha256": "475dcae1e7d1ea46232db6f8481040c15e53a52a3c256831d3df204212b0e831" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd", + "sha256": "0b364451dc36a48dd6dae0f3b6ada05fd9b71e5208211f8ee5537d7e51a587e2" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd", + "sha256": "bc92e36ccd233722d4c5869bec71ddc7b12e2df56059942cce5a39065cc9c368" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd", + "sha256": "f5ee623b08b6a66935e5aced2f5d8ad0fc71bf9e8e833cd490150c0fa94b8763" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd", + "sha256": "a539aa2fb154fa50e0f5cc97e6ad7cbc66f8ec3e3746f61ec6a8b0d5d15ecdf2" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd", + "sha256": "12264f3c03d738311cd9237d212f1c07479e70f0cbe1ae725d29b36539aef637" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd", + "sha256": "0ef4bb354ff44b923564c4ddbdda5987919d220225129ec94614a618ceafc281" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd", + "sha256": "7b5b7413e2c895b1e148e82e292a117d53c7ec65b0696c992edca57b61b4a74b" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd", + "sha256": "3213ef1631606250f5010b42cad7ef716f7c59426367798e33c374c0ec391d3a" + }, + { + "path": "skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd", + "sha256": "3c6709101c6aaa82888df5d8795c33f9e857196790eb320d9194e64be2b6bdd8" + }, + { + "path": "skills/docx/ooxml/scripts/pack.py", + "sha256": "6fe762f45aff8c63fd95b9fcb1337b28921d6fa454e18a0e8158d4c8708d6d00" + }, + { + "path": "skills/docx/ooxml/scripts/validate.py", + "sha256": "1ec252de8b14b07d16966c48906ccb1c45c68bcd23557ad31d8c50a27f5f8c0f" + }, + { + "path": "skills/docx/ooxml/scripts/unpack.py", + "sha256": "0bd17f76a1a4c388aba42c6d1d39015fa84e405c3e0692397fe12762bd632b58" + }, + { + "path": "skills/docx/ooxml/scripts/validation/docx.py", + "sha256": "e65d6cda0525866a24cc847b2e883bd2416ae6f87b3f5b9e2784dfbb0ec13093" + }, + { + "path": "skills/docx/ooxml/scripts/validation/__init__.py", + "sha256": "83e0f035c5abea238d3f2c3968afbd511ed022b527b7c9cb60a9434cc34ff987" + }, + { + "path": "skills/docx/ooxml/scripts/validation/redlining.py", + "sha256": "97abfdff4f08f43f9a4bb5c8a2f8fd483398b5b339592724e8635153b5507967" + }, + { + "path": "skills/docx/ooxml/scripts/validation/pptx.py", + "sha256": "00bf2623da1177b3948143a4ade2f1cda7cb389dee31960861913fa42ef1b00f" + }, + { + "path": "skills/docx/ooxml/scripts/validation/base.py", + "sha256": "f2c70d481613456e32b43869d1604b05c236c8da34b5b3967677a661cac7ba63" + }, + { + "path": "skills/docx/scripts/__init__.py", + "sha256": "83e262a425814b72add701272b99ddcf9635251c5d4672bf9fc38d2b03f00d85" + }, + { + "path": "skills/docx/scripts/document.py", + "sha256": "65f8569034a5893bd5ef0654be5168774fe81c0407b0c4ec80992db9fff91c0c" + }, + { + "path": "skills/docx/scripts/utilities.py", + "sha256": "62a4b689056501b91e2df2d1f4e6335818e421c7390e48050717ea8f461a0ed0" + }, + { + "path": "skills/docx/scripts/templates/comments.xml", + "sha256": "87e218a3a295016ec855f2cd74495c416072f29c4846e86b527aec0a4d93ba21" + }, + { + "path": "skills/docx/scripts/templates/commentsExtensible.xml", + "sha256": "af5d057e16462ca172cea845e502bafb4f3e1b474a8d5848ffe92214853a4935" + }, + { + "path": "skills/docx/scripts/templates/commentsExtended.xml", + "sha256": "86bf401354c111102033ed147763faccb82479598f17777a3384c2f3e9fa0014" + }, + { + "path": "skills/docx/scripts/templates/commentsIds.xml", + "sha256": "20168f7b237af091332f8348c548eb7f755f583185bb198359c5978155099d67" + }, + { + "path": "skills/docx/scripts/templates/people.xml", + "sha256": "61db9900b579acd4c4f84ff7f40df47e77e9e780c40d5f5ef6a7beba41d62ec5" + }, + { + "path": "skills/browser-control/bun.lock", + "sha256": "1628b5fa9e0d09288d5c3167256636ec27437064c1ccb17f995c44754d70600f" + }, + { + "path": "skills/browser-control/package.json", + "sha256": "a13322256de1012d06e2cfa29f561ed7d5c0c8213f4027e8d1f3ab0e33194f50" + }, + { + "path": "skills/browser-control/SKILL.md", + "sha256": "98cf3e5b6c79501ffa18d53bbd4c6e9a407dfbe12e2af44507735f7732697b42" + }, + { + "path": "skills/browser-control/scripts/launch-chrome.sh", + "sha256": "f0ad9a1177686d55c6278f031b03a8e2f5b5e4833e63c631148d93d45020c36e" + }, + { + "path": "skills/browser-control/scripts/navigate.js", + "sha256": "6544c08680a29547d386fd0c0b6a6ad38af65e07a3879087b8f92cfe8a3958eb" + }, + { + "path": "skills/browser-control/scripts/screenshot.js", + "sha256": "bf53dc73f47b32ed449bee2f1944231284411cbbba18097ff6dc4c1af90535a9" + }, + { + "path": "skills/browser-control/scripts/extract.js", + "sha256": "07d2a0b18115251a30cbb5395ff251b32bc3cf115d2923ebfb598407efc26c3b" + }, + { + "path": "skills/browser-control/scripts/interact.js", + "sha256": "20f6b2eecb53d8ded16d19e8c600435cad051a4830a4a835893971a7f79effb4" + }, + { + "path": "skills/browser-control/scripts/capture.js", + "sha256": "fd1e646615a309f90f22227c626270b7c32bb9eaa5e38068aa021ad6419d3450" + }, + { + "path": "skills/browser-control/scripts/search.js", + "sha256": "55d1952796ad776d944ccfffd4623bd2107dd0d9bddea736964f54c4717a9a7b" + } + ], + "dirSha256": "64ed8ff88264cec7703698104d9fdd868330a37557d0a947a3e9ab5c2303e116" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/skills/browser-control/SKILL.md b/skills/browser-control/SKILL.md new file mode 100644 index 0000000..a2d5c49 --- /dev/null +++ b/skills/browser-control/SKILL.md @@ -0,0 +1,123 @@ +--- +name: browser-control +description: Full browser control for authenticated web interactions using Playwright scripts +triggers: + - "check availability" + - "search for" + - "log into" + - "browse to" + - "look up prices" + - "check points" + - "find deals" + - "scrape" + - "get current price" + - "check hotel" + - "check flight" +allowed-tools: Bash, Read +version: 0.1.0 +--- + +# Browser Control Skill + +Full browser automation for travel research requiring authentication or complex interactions. + +## When to Activate + +Use this skill when you need to: +- Access authenticated pages (Marriott, Alaska Airlines accounts) +- Check real-time availability and prices +- Scrape forum threads (FlyerTalk, Reddit) +- Interact with JavaScript-heavy travel sites +- Fill forms or perform searches on websites + +## Architecture + +**Script-based approach** - No MCP overhead. Scripts load only when needed. + +### Prerequisites + +1. **Geoffrey Chrome Profile** must be running with remote debugging: + ```bash + ./scripts/launch-chrome.sh + ``` + +2. **Profile must have logins saved** for: + - Marriott Bonvoy + - Alaska Airlines Mileage Plan + - FlyerTalk + - TripAdvisor + - Reddit + +## Available Scripts + +All scripts are in `./scripts/` and use Playwright connecting via CDP. + +| Script | Purpose | Usage | +|--------|---------|-------| +| `launch-chrome.sh` | Start Geoffrey Chrome profile | `./scripts/launch-chrome.sh` | +| `navigate.js` | Navigate to URL and get page content | `bun scripts/navigate.js ` | +| `screenshot.js` | Take screenshot of page | `bun scripts/screenshot.js [output] [--full]` | +| `extract.js` | Extract text/data from page | `bun scripts/extract.js [--all]` | +| `interact.js` | Click, type, select on page | `bun scripts/interact.js [value]` | +| `search.js` | Search travel sites | `bun scripts/search.js ` | + +## Usage Examples + +### Check Marriott Points Availability +```bash +# Navigate to Marriott search +bun scripts/navigate.js "https://www.marriott.com/search/default.mi" + +# Or use the search script +bun scripts/search.js marriott "Westin Rusutsu February 2026" +``` + +### Get FlyerTalk Thread Content +```bash +bun scripts/extract.js "https://www.flyertalk.com/forum/thread-url" ".post-content" +``` + +### Screenshot Hotel Page +```bash +bun scripts/screenshot.js "https://www.marriott.com/hotels/travel/ctswi-the-westin-rusutsu-resort/" rusutsu.png +``` + +## Connection Details + +Scripts connect to Chrome via Chrome DevTools Protocol (CDP): +- **URL**: `http://127.0.0.1:9222` +- **Profile**: `~/.chrome-geoffrey` + +## Error Handling + +If scripts fail to connect: +1. Ensure Chrome is running with `./scripts/launch-chrome.sh` +2. Check port 9222 is not in use: `lsof -i :9222` +3. Kill existing Chrome debugger: `pkill -f "remote-debugging-port"` + +## Output Format + +All scripts return JSON: +```json +{ + "success": true, + "url": "https://example.com", + "title": "Page Title", + "content": "Extracted content or action result", + "timestamp": "2025-11-22T..." +} +``` + +## Limitations + +- Requires Geoffrey Chrome profile to be running +- Cannot bypass CAPTCHAs (uses real browser fingerprint to avoid most) +- Heavy sites may be slow +- Some sites block automation despite real browser + +## Future Enhancements + +- Add cookie/session export for headless runs +- 1Password CLI integration for credential rotation +- Parallel page operations +- Browser-Use (Python) for complex visual tasks diff --git a/skills/browser-control/bun.lock b/skills/browser-control/bun.lock new file mode 100644 index 0000000..15f6b27 --- /dev/null +++ b/skills/browser-control/bun.lock @@ -0,0 +1,180 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "browser-control", + "dependencies": { + "puppeteer-core": "^23.0.0", + }, + }, + }, + "packages": { + "@puppeteer/browsers": ["@puppeteer/browsers@2.6.1", "", { "dependencies": { "debug": "^4.4.0", "extract-zip": "^2.0.1", "progress": "^2.0.3", "proxy-agent": "^6.5.0", "semver": "^7.6.3", "tar-fs": "^3.0.6", "unbzip2-stream": "^1.4.3", "yargs": "^17.7.2" }, "bin": { "browsers": "lib/cjs/main-cli.js" } }, "sha512-aBSREisdsGH890S2rQqK82qmQYU3uFpSH8wcZWHgHzl3LfzsxAKbLNiAG9mO8v1Y0UICBeClICxPJvyr0rcuxg=="], + + "@tootallnate/quickjs-emscripten": ["@tootallnate/quickjs-emscripten@0.23.0", "", {}, "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA=="], + + "@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="], + + "@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="], + + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "ast-types": ["ast-types@0.13.4", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w=="], + + "b4a": ["b4a@1.7.3", "", { "peerDependencies": { "react-native-b4a": "*" }, "optionalPeers": ["react-native-b4a"] }, "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q=="], + + "bare-events": ["bare-events@2.8.2", "", { "peerDependencies": { "bare-abort-controller": "*" }, "optionalPeers": ["bare-abort-controller"] }, "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ=="], + + "bare-fs": ["bare-fs@4.5.1", "", { "dependencies": { "bare-events": "^2.5.4", "bare-path": "^3.0.0", "bare-stream": "^2.6.4", "bare-url": "^2.2.2", "fast-fifo": "^1.3.2" }, "peerDependencies": { "bare-buffer": "*" }, "optionalPeers": ["bare-buffer"] }, "sha512-zGUCsm3yv/ePt2PHNbVxjjn0nNB1MkIaR4wOCxJ2ig5pCf5cCVAYJXVhQg/3OhhJV6DB1ts7Hv0oUaElc2TPQg=="], + + "bare-os": ["bare-os@3.6.2", "", {}, "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A=="], + + "bare-path": ["bare-path@3.0.0", "", { "dependencies": { "bare-os": "^3.0.1" } }, "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw=="], + + "bare-stream": ["bare-stream@2.7.0", "", { "dependencies": { "streamx": "^2.21.0" }, "peerDependencies": { "bare-buffer": "*", "bare-events": "*" }, "optionalPeers": ["bare-buffer", "bare-events"] }, "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A=="], + + "bare-url": ["bare-url@2.3.2", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "basic-ftp": ["basic-ftp@5.0.5", "", {}, "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg=="], + + "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + + "buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="], + + "chromium-bidi": ["chromium-bidi@0.11.0", "", { "dependencies": { "mitt": "3.0.1", "zod": "3.23.8" }, "peerDependencies": { "devtools-protocol": "*" } }, "sha512-6CJWHkNRoyZyjV9Rwv2lYONZf1Xm0IuDyNq97nwSsxxP3wf5Bwy15K5rOvVKMtJ127jJBmxFUanSAOjgFRxgrA=="], + + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "data-uri-to-buffer": ["data-uri-to-buffer@6.0.2", "", {}, "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "degenerator": ["degenerator@5.0.1", "", { "dependencies": { "ast-types": "^0.13.4", "escodegen": "^2.1.0", "esprima": "^4.0.1" } }, "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ=="], + + "devtools-protocol": ["devtools-protocol@0.0.1367902", "", {}, "sha512-XxtPuC3PGakY6PD7dG66/o8KwJ/LkH2/EKe19Dcw58w53dv4/vSQEkn/SzuyhHE2q4zPgCkxQBxus3VV4ql+Pg=="], + + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "escodegen": ["escodegen@2.1.0", "", { "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2" }, "optionalDependencies": { "source-map": "~0.6.1" }, "bin": { "esgenerate": "bin/esgenerate.js", "escodegen": "bin/escodegen.js" } }, "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w=="], + + "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], + + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + + "events-universal": ["events-universal@1.0.1", "", { "dependencies": { "bare-events": "^2.7.0" } }, "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw=="], + + "extract-zip": ["extract-zip@2.0.1", "", { "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "optionalDependencies": { "@types/yauzl": "^2.9.1" }, "bin": { "extract-zip": "cli.js" } }, "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg=="], + + "fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="], + + "fd-slicer": ["fd-slicer@1.1.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="], + + "get-uri": ["get-uri@6.0.5", "", { "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4" } }, "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg=="], + + "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], + + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="], + + "mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "netmask": ["netmask@2.0.2", "", {}, "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "pac-proxy-agent": ["pac-proxy-agent@7.2.0", "", { "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", "agent-base": "^7.1.2", "debug": "^4.3.4", "get-uri": "^6.0.1", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.6", "pac-resolver": "^7.0.1", "socks-proxy-agent": "^8.0.5" } }, "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA=="], + + "pac-resolver": ["pac-resolver@7.0.1", "", { "dependencies": { "degenerator": "^5.0.0", "netmask": "^2.0.2" } }, "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg=="], + + "pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="], + + "progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="], + + "proxy-agent": ["proxy-agent@6.5.0", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "http-proxy-agent": "^7.0.1", "https-proxy-agent": "^7.0.6", "lru-cache": "^7.14.1", "pac-proxy-agent": "^7.1.0", "proxy-from-env": "^1.1.0", "socks-proxy-agent": "^8.0.5" } }, "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A=="], + + "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], + + "pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="], + + "puppeteer-core": ["puppeteer-core@23.11.1", "", { "dependencies": { "@puppeteer/browsers": "2.6.1", "chromium-bidi": "0.11.0", "debug": "^4.4.0", "devtools-protocol": "0.0.1367902", "typed-query-selector": "^2.12.0", "ws": "^8.18.0" } }, "sha512-3HZ2/7hdDKZvZQ7dhhITOUg4/wOrDRjyK2ZBllRB0ZCOi9u0cwq1ACHDjBB+nX+7+kltHjQvBRdeY7+W0T+7Gg=="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], + + "socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="], + + "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], + + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "streamx": ["streamx@2.23.0", "", { "dependencies": { "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" } }, "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg=="], + + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "tar-fs": ["tar-fs@3.1.1", "", { "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" }, "optionalDependencies": { "bare-fs": "^4.0.1", "bare-path": "^3.0.0" } }, "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg=="], + + "tar-stream": ["tar-stream@3.1.7", "", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="], + + "text-decoder": ["text-decoder@1.2.3", "", { "dependencies": { "b4a": "^1.6.4" } }, "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA=="], + + "through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "typed-query-selector": ["typed-query-selector@2.12.0", "", {}, "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg=="], + + "unbzip2-stream": ["unbzip2-stream@1.4.3", "", { "dependencies": { "buffer": "^5.2.1", "through": "^2.3.8" } }, "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg=="], + + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], + + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + + "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="], + + "zod": ["zod@3.23.8", "", {}, "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g=="], + } +} diff --git a/skills/browser-control/package.json b/skills/browser-control/package.json new file mode 100644 index 0000000..f6e2137 --- /dev/null +++ b/skills/browser-control/package.json @@ -0,0 +1,15 @@ +{ + "name": "browser-control", + "version": "0.1.0", + "description": "Browser control scripts for Geoffrey using Playwright", + "type": "module", + "scripts": { + "launch": "./scripts/launch-chrome.sh", + "navigate": "bun scripts/navigate.js", + "screenshot": "bun scripts/screenshot.js", + "extract": "bun scripts/extract.js" + }, + "dependencies": { + "puppeteer-core": "^23.0.0" + } +} diff --git a/skills/browser-control/scripts/capture.js b/skills/browser-control/scripts/capture.js new file mode 100644 index 0000000..d159877 --- /dev/null +++ b/skills/browser-control/scripts/capture.js @@ -0,0 +1,75 @@ +#!/usr/bin/env bun + +/** + * Capture current page state (no navigation) + * + * Usage: bun capture.js [output.png] + */ + +import puppeteer from 'puppeteer-core'; +import path from 'path'; + +const CDP_ENDPOINT = 'http://127.0.0.1:9222'; + +async function capture(outputPath) { + let browser; + + try { + browser = await puppeteer.connect({ + browserURL: CDP_ENDPOINT, + defaultViewport: null + }); + + const pages = await browser.pages(); + if (pages.length === 0) { + throw new Error('No pages open in browser'); + } + + const page = pages[0]; + const url = page.url(); + const title = await page.title(); + + // Take screenshot if output path provided + if (outputPath) { + await page.screenshot({ path: outputPath }); + } + + // Get content + const content = await page.evaluate(() => { + const main = document.querySelector('main') || + document.querySelector('article') || + document.querySelector('#content') || + document.body; + return main.innerText.substring(0, 10000); + }); + + return { + success: true, + url, + title, + content, + screenshot: outputPath ? path.resolve(outputPath) : null, + timestamp: new Date().toISOString() + }; + + } catch (error) { + return { + success: false, + error: error.message, + timestamp: new Date().toISOString() + }; + } finally { + if (browser) { + browser.disconnect(); + } + } +} + +async function main() { + const outputPath = process.argv[2] || null; + const result = await capture(outputPath); + console.log(JSON.stringify(result, null, 2)); + if (!result.success) process.exit(1); +} + +main(); diff --git a/skills/browser-control/scripts/extract.js b/skills/browser-control/scripts/extract.js new file mode 100644 index 0000000..4c23a03 --- /dev/null +++ b/skills/browser-control/scripts/extract.js @@ -0,0 +1,93 @@ +#!/usr/bin/env bun + +/** + * Extract content from webpage using CSS selectors + * + * Usage: bun extract.js [--all] [--attr ] + */ + +import puppeteer from 'puppeteer-core'; + +const CDP_ENDPOINT = 'http://127.0.0.1:9222'; + +async function extract(url, selector, options = {}) { + let browser; + + try { + browser = await puppeteer.connect({ + browserURL: CDP_ENDPOINT, + defaultViewport: null + }); + + const page = await browser.newPage(); + + await page.goto(url, { + waitUntil: 'domcontentloaded', + timeout: 30000 + }); + + await page.waitForSelector(selector, { timeout: 10000 }); + + let extracted; + + if (options.all) { + extracted = await page.$$eval(selector, (elements, attr) => { + return elements.map(el => attr ? el.getAttribute(attr) : el.innerText.trim()); + }, options.attr); + } else { + extracted = await page.$eval(selector, (el, attr) => { + return attr ? el.getAttribute(attr) : el.innerText.trim(); + }, options.attr); + } + + const title = await page.title(); + await page.close(); + + return { + success: true, + url, + title, + selector, + extracted, + count: options.all ? extracted.length : 1, + timestamp: new Date().toISOString() + }; + + } catch (error) { + return { + success: false, + url, + selector, + error: error.message, + timestamp: new Date().toISOString() + }; + } finally { + if (browser) browser.disconnect(); + } +} + +async function main() { + const args = process.argv.slice(2); + const url = args[0]; + const selector = args[1]; + + if (!url || !selector) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'bun extract.js [--all] [--attr ]' + })); + process.exit(1); + } + + const options = {}; + for (let i = 2; i < args.length; i++) { + if (args[i] === '--all') options.all = true; + else if (args[i] === '--attr') options.attr = args[++i]; + } + + const result = await extract(url, selector, options); + console.log(JSON.stringify(result, null, 2)); + if (!result.success) process.exit(1); +} + +main(); diff --git a/skills/browser-control/scripts/interact.js b/skills/browser-control/scripts/interact.js new file mode 100644 index 0000000..bed8514 --- /dev/null +++ b/skills/browser-control/scripts/interact.js @@ -0,0 +1,96 @@ +#!/usr/bin/env bun + +/** + * Interact with webpage elements (click, type, select) + * + * Usage: bun interact.js [value] + */ + +import puppeteer from 'puppeteer-core'; + +const CDP_ENDPOINT = 'http://127.0.0.1:9222'; + +async function interact(url, action, selector, value = null) { + let browser; + + try { + browser = await puppeteer.connect({ + browserURL: CDP_ENDPOINT, + defaultViewport: null + }); + + const page = await browser.newPage(); + + await page.goto(url, { + waitUntil: 'domcontentloaded', + timeout: 30000 + }); + + await page.waitForSelector(selector, { timeout: 10000 }); + + let result; + + switch (action) { + case 'click': + await page.click(selector); + result = 'clicked'; + break; + case 'type': + await page.type(selector, value); + result = `typed: ${value}`; + break; + case 'select': + await page.select(selector, value); + result = `selected: ${value}`; + break; + default: + throw new Error(`Unknown action: ${action}`); + } + + await page.waitForTimeout(1000); + const title = await page.title(); + const finalUrl = page.url(); + await page.close(); + + return { + success: true, + url: finalUrl, + title, + action, + selector, + result, + timestamp: new Date().toISOString() + }; + + } catch (error) { + return { + success: false, + url, + action, + selector, + error: error.message, + timestamp: new Date().toISOString() + }; + } finally { + if (browser) browser.disconnect(); + } +} + +async function main() { + const args = process.argv.slice(2); + const [url, action, selector, value] = args; + + if (!url || !action || !selector) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'bun interact.js [value]' + })); + process.exit(1); + } + + const result = await interact(url, action, selector, value); + console.log(JSON.stringify(result, null, 2)); + if (!result.success) process.exit(1); +} + +main(); diff --git a/skills/browser-control/scripts/launch-chrome.sh b/skills/browser-control/scripts/launch-chrome.sh new file mode 100755 index 0000000..3feea88 --- /dev/null +++ b/skills/browser-control/scripts/launch-chrome.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# Launch Geoffrey Chrome Profile with Remote Debugging +# +# This starts a dedicated Chrome profile for Geoffrey's browser automation. +# The profile persists logins, cookies, and extensions between sessions. +# +# Usage: ./launch-chrome.sh [--headless] + +PROFILE_DIR="$HOME/.brave-geoffrey" +PORT=9222 + +# Check if Chrome is already running with debugging +if lsof -i :$PORT > /dev/null 2>&1; then + echo '{"status": "already_running", "port": '$PORT', "profile": "'$PROFILE_DIR'"}' + exit 0 +fi + +# Create profile directory if it doesn't exist +if [ ! -d "$PROFILE_DIR" ]; then + mkdir -p "$PROFILE_DIR" + echo "Created new Geoffrey Chrome profile at $PROFILE_DIR" + echo "Please log into your accounts (Marriott, Alaska, etc.) on first run." +fi + +# Check for headless flag +HEADLESS="" +if [ "$1" = "--headless" ]; then + HEADLESS="--headless=new" +fi + +# Launch Brave Nightly with remote debugging (bypasses district MDM) +/Applications/Brave\ Browser\ Nightly.app/Contents/MacOS/Brave\ Browser\ Nightly \ + --remote-debugging-port=$PORT \ + --user-data-dir="$PROFILE_DIR" \ + $HEADLESS \ + --no-first-run \ + --no-default-browser-check \ + & + +# Wait for Chrome to start +sleep 2 + +# Verify it's running +if lsof -i :$PORT > /dev/null 2>&1; then + echo '{"status": "started", "port": '$PORT', "profile": "'$PROFILE_DIR'", "headless": "'$HEADLESS'"}' +else + echo '{"status": "failed", "error": "Chrome did not start on port '$PORT'"}' + exit 1 +fi diff --git a/skills/browser-control/scripts/navigate.js b/skills/browser-control/scripts/navigate.js new file mode 100644 index 0000000..15d3765 --- /dev/null +++ b/skills/browser-control/scripts/navigate.js @@ -0,0 +1,113 @@ +#!/usr/bin/env bun + +/** + * Navigate to URL and return page content + * + * Connects to Geoffrey's browser profile via CDP and navigates to the specified URL. + * Returns page title, URL, and text content. + * + * Usage: bun navigate.js [--wait ] + * + * Examples: + * bun navigate.js https://www.marriott.com + * bun navigate.js https://flyertalk.com/forum --wait ".post-content" + */ + +import puppeteer from 'puppeteer-core'; + +const CDP_ENDPOINT = 'http://127.0.0.1:9222'; + +async function navigate(url, options = {}) { + let browser; + + try { + // Connect to existing browser instance via CDP + browser = await puppeteer.connect({ + browserURL: CDP_ENDPOINT, + defaultViewport: null + }); + + // Always create a new page to avoid interfering with user's tabs + const page = await browser.newPage(); + + // Navigate to URL + await page.goto(url, { + waitUntil: 'domcontentloaded', + timeout: 30000 + }); + + // Wait for specific selector if provided + if (options.waitFor) { + await page.waitForSelector(options.waitFor, { timeout: 10000 }); + } + + // Get page info + const title = await page.title(); + const content = await page.evaluate(() => { + // Get main content, avoiding nav/footer + const main = document.querySelector('main') || + document.querySelector('article') || + document.querySelector('#content') || + document.body; + return main.innerText.substring(0, 10000); // Limit content size + }); + + // Get current URL (may have redirected) + const finalUrl = page.url(); + + return { + success: true, + url: finalUrl, + title, + content, + timestamp: new Date().toISOString() + }; + + } catch (error) { + return { + success: false, + url, + error: error.message, + hint: error.message.includes('connect') || error.message.includes('ECONNREFUSED') + ? 'Is browser running? Start with: ./scripts/launch-chrome.sh' + : null, + timestamp: new Date().toISOString() + }; + } finally { + // Disconnect (don't close - we want browser to stay open) + if (browser) { + browser.disconnect(); + } + } +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const url = args[0]; + + if (!url) { + console.error(JSON.stringify({ + error: 'Missing URL', + usage: 'bun navigate.js [--wait ]' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 1; i < args.length; i++) { + if (args[i] === '--wait') { + options.waitFor = args[++i]; + } + } + + const result = await navigate(url, options); + console.log(JSON.stringify(result, null, 2)); + + if (!result.success) { + process.exit(1); + } +} + +main(); diff --git a/skills/browser-control/scripts/screenshot.js b/skills/browser-control/scripts/screenshot.js new file mode 100644 index 0000000..b721e3a --- /dev/null +++ b/skills/browser-control/scripts/screenshot.js @@ -0,0 +1,110 @@ +#!/usr/bin/env bun + +/** + * Take screenshot of a webpage + * + * Usage: bun screenshot.js [output.png] [--full] + * + * Options: + * --full Capture full page (not just viewport) + * + * Examples: + * bun screenshot.js https://www.marriott.com + * bun screenshot.js https://www.marriott.com hotel.png --full + */ + +import puppeteer from 'puppeteer-core'; +import path from 'path'; + +const CDP_ENDPOINT = 'http://127.0.0.1:9222'; + +async function screenshot(url, outputPath, options = {}) { + let browser; + + try { + browser = await puppeteer.connect({ + browserURL: CDP_ENDPOINT, + defaultViewport: null + }); + + const pages = await browser.pages(); + const page = pages.length > 0 ? pages[0] : await browser.newPage(); + + await page.goto(url, { + waitUntil: 'networkidle2', + timeout: 30000 + }); + + // Default output path + if (!outputPath) { + const urlObj = new URL(url); + outputPath = `screenshot-${urlObj.hostname}-${Date.now()}.png`; + } + + // Take screenshot + await page.screenshot({ + path: outputPath, + fullPage: options.fullPage || false + }); + + const title = await page.title(); + + return { + success: true, + url, + title, + screenshot: path.resolve(outputPath), + fullPage: options.fullPage || false, + timestamp: new Date().toISOString() + }; + + } catch (error) { + return { + success: false, + url, + error: error.message, + hint: error.message.includes('connect') || error.message.includes('ECONNREFUSED') + ? 'Is browser running? Start with: ./scripts/launch-chrome.sh' + : null, + timestamp: new Date().toISOString() + }; + } finally { + if (browser) { + browser.disconnect(); + } + } +} + +async function main() { + const args = process.argv.slice(2); + const url = args[0]; + + if (!url) { + console.error(JSON.stringify({ + error: 'Missing URL', + usage: 'bun screenshot.js [output.png] [--full]' + })); + process.exit(1); + } + + // Parse args + let outputPath = null; + const options = {}; + + for (let i = 1; i < args.length; i++) { + if (args[i] === '--full') { + options.fullPage = true; + } else if (!args[i].startsWith('--')) { + outputPath = args[i]; + } + } + + const result = await screenshot(url, outputPath, options); + console.log(JSON.stringify(result, null, 2)); + + if (!result.success) { + process.exit(1); + } +} + +main(); diff --git a/skills/browser-control/scripts/search.js b/skills/browser-control/scripts/search.js new file mode 100644 index 0000000..af20598 --- /dev/null +++ b/skills/browser-control/scripts/search.js @@ -0,0 +1,129 @@ +#!/usr/bin/env bun + +/** + * Perform searches on common travel sites + * + * Usage: bun search.js + */ + +import puppeteer from 'puppeteer-core'; + +const CDP_ENDPOINT = 'http://127.0.0.1:9222'; + +const SITES = { + marriott: { + url: (q) => `https://www.marriott.com/search/default.mi?keywords=${encodeURIComponent(q)}`, + resultSelector: '.property-card, .l-container' + }, + alaska: { + url: 'https://www.alaskaair.com/', + resultSelector: '.search-results' + }, + flyertalk: { + url: (q) => `https://www.flyertalk.com/forum/search.php?do=process&query=${encodeURIComponent(q)}`, + resultSelector: '.searchresult, .threadbit' + }, + tripadvisor: { + url: (q) => `https://www.tripadvisor.com/Search?q=${encodeURIComponent(q)}`, + resultSelector: '[data-automation="searchResult"]' + }, + reddit: { + url: (q) => `https://www.reddit.com/search/?q=${encodeURIComponent(q)}`, + resultSelector: '[data-testid="post-container"]' + }, + google: { + url: (q) => `https://www.google.com/search?q=${encodeURIComponent(q)}`, + resultSelector: '.g' + } +}; + +async function search(siteName, query) { + let browser; + + try { + const site = SITES[siteName.toLowerCase()]; + if (!site) { + return { + success: false, + error: `Unknown site: ${siteName}`, + availableSites: Object.keys(SITES) + }; + } + + browser = await puppeteer.connect({ + browserURL: CDP_ENDPOINT, + defaultViewport: null + }); + + const page = await browser.newPage(); + const url = typeof site.url === 'function' ? site.url(query) : site.url; + + await page.goto(url, { + waitUntil: 'domcontentloaded', + timeout: 30000 + }); + + let results = []; + try { + await page.waitForSelector(site.resultSelector, { timeout: 10000 }); + results = await page.$$eval(site.resultSelector, (elements) => { + return elements.slice(0, 10).map(el => { + const link = el.querySelector('a'); + return { + text: el.innerText.substring(0, 500).trim(), + url: link ? link.href : null + }; + }); + }); + } catch (e) { + // No results found + } + + const title = await page.title(); + const finalUrl = page.url(); + await page.close(); + + return { + success: true, + site: siteName, + query, + url: finalUrl, + title, + resultCount: results.length, + results, + timestamp: new Date().toISOString() + }; + + } catch (error) { + return { + success: false, + site: siteName, + query, + error: error.message, + timestamp: new Date().toISOString() + }; + } finally { + if (browser) browser.disconnect(); + } +} + +async function main() { + const args = process.argv.slice(2); + const site = args[0]; + const query = args.slice(1).join(' '); + + if (!site || !query) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'bun search.js ', + availableSites: Object.keys(SITES) + })); + process.exit(1); + } + + const result = await search(site, query); + console.log(JSON.stringify(result, null, 2)); + if (!result.success) process.exit(1); +} + +main(); diff --git a/skills/docx/LICENSE.txt b/skills/docx/LICENSE.txt new file mode 100644 index 0000000..c55ab42 --- /dev/null +++ b/skills/docx/LICENSE.txt @@ -0,0 +1,30 @@ +© 2025 Anthropic, PBC. All rights reserved. + +LICENSE: Use of these materials (including all code, prompts, assets, files, +and other components of this Skill) is governed by your agreement with +Anthropic regarding use of Anthropic's services. If no separate agreement +exists, use is governed by Anthropic's Consumer Terms of Service or +Commercial Terms of Service, as applicable: +https://www.anthropic.com/legal/consumer-terms +https://www.anthropic.com/legal/commercial-terms +Your applicable agreement is referred to as the "Agreement." "Services" are +as defined in the Agreement. + +ADDITIONAL RESTRICTIONS: Notwithstanding anything in the Agreement to the +contrary, users may not: + +- Extract these materials from the Services or retain copies of these + materials outside the Services +- Reproduce or copy these materials, except for temporary copies created + automatically during authorized use of the Services +- Create derivative works based on these materials +- Distribute, sublicense, or transfer these materials to any third party +- Make, offer to sell, sell, or import any inventions embodied in these + materials +- Reverse engineer, decompile, or disassemble these materials + +The receipt, viewing, or possession of these materials does not convey or +imply any license or right beyond those expressly granted above. + +Anthropic retains all right, title, and interest in these materials, +including all copyrights, patents, and other intellectual property rights. diff --git a/skills/docx/SKILL.md b/skills/docx/SKILL.md new file mode 100644 index 0000000..88fd94d --- /dev/null +++ b/skills/docx/SKILL.md @@ -0,0 +1,206 @@ +--- +name: docx +description: "Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. When Claude needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks" +triggers: + - "create word document" + - "edit docx" + - "word file" + - "track changes" + - "docx" + - ".docx" +allowed-tools: Read, Write, Edit, Bash, Glob +version: 1.0.0 +license: Proprietary. LICENSE.txt has complete terms +--- + +# DOCX creation, editing, and analysis + +## Overview + +A user may ask you to create, edit, or analyze the contents of a .docx file. A .docx file is essentially a ZIP archive containing XML files and other resources that you can read or edit. You have different tools and workflows available for different tasks. + +## Workflow Decision Tree + +### Reading/Analyzing Content +Use "Text extraction" or "Raw XML access" sections below + +### Creating New Document +Use "Creating a new Word document" workflow + +### Editing Existing Document +- **Your own document + simple changes** + Use "Basic OOXML editing" workflow + +- **Someone else's document** + Use **"Redlining workflow"** (recommended default) + +- **Legal, academic, business, or government docs** + Use **"Redlining workflow"** (required) + +## Reading and analyzing content + +### Text extraction +If you just need to read the text contents of a document, you should convert the document to markdown using pandoc. Pandoc provides excellent support for preserving document structure and can show tracked changes: + +```bash +# Convert document to markdown with tracked changes +pandoc --track-changes=all path-to-file.docx -o output.md +# Options: --track-changes=accept/reject/all +``` + +### Raw XML access +You need raw XML access for: comments, complex formatting, document structure, embedded media, and metadata. For any of these features, you'll need to unpack a document and read its raw XML contents. + +#### Unpacking a file +`python ooxml/scripts/unpack.py ` + +#### Key file structures +* `word/document.xml` - Main document contents +* `word/comments.xml` - Comments referenced in document.xml +* `word/media/` - Embedded images and media files +* Tracked changes use `` (insertions) and `` (deletions) tags + +## Creating a new Word document + +When creating a new Word document from scratch, use **docx-js**, which allows you to create Word documents using JavaScript/TypeScript. + +### Workflow +1. **MANDATORY - READ ENTIRE FILE**: Read [`docx-js.md`](docx-js.md) (~500 lines) completely from start to finish. **NEVER set any range limits when reading this file.** Read the full file content for detailed syntax, critical formatting rules, and best practices before proceeding with document creation. +2. Create a JavaScript/TypeScript file using Document, Paragraph, TextRun components (You can assume all dependencies are installed, but if not, refer to the dependencies section below) +3. Export as .docx using Packer.toBuffer() + +## Editing an existing Word document + +When editing an existing Word document, use the **Document library** (a Python library for OOXML manipulation). The library automatically handles infrastructure setup and provides methods for document manipulation. For complex scenarios, you can access the underlying DOM directly through the library. + +### Workflow +1. **MANDATORY - READ ENTIRE FILE**: Read [`ooxml.md`](ooxml.md) (~600 lines) completely from start to finish. **NEVER set any range limits when reading this file.** Read the full file content for the Document library API and XML patterns for directly editing document files. +2. Unpack the document: `python ooxml/scripts/unpack.py ` +3. Create and run a Python script using the Document library (see "Document Library" section in ooxml.md) +4. Pack the final document: `python ooxml/scripts/pack.py ` + +The Document library provides both high-level methods for common operations and direct DOM access for complex scenarios. + +## Redlining workflow for document review + +This workflow allows you to plan comprehensive tracked changes using markdown before implementing them in OOXML. **CRITICAL**: For complete tracked changes, you must implement ALL changes systematically. + +**Batching Strategy**: Group related changes into batches of 3-10 changes. This makes debugging manageable while maintaining efficiency. Test each batch before moving to the next. + +**Principle: Minimal, Precise Edits** +When implementing tracked changes, only mark text that actually changes. Repeating unchanged text makes edits harder to review and appears unprofessional. Break replacements into: [unchanged text] + [deletion] + [insertion] + [unchanged text]. Preserve the original run's RSID for unchanged text by extracting the `` element from the original and reusing it. + +Example - Changing "30 days" to "60 days" in a sentence: +```python +# BAD - Replaces entire sentence +'The term is 30 days.The term is 60 days.' + +# GOOD - Only marks what changed, preserves original for unchanged text +'The term is 3060 days.' +``` + +### Tracked changes workflow + +1. **Get markdown representation**: Convert document to markdown with tracked changes preserved: + ```bash + pandoc --track-changes=all path-to-file.docx -o current.md + ``` + +2. **Identify and group changes**: Review the document and identify ALL changes needed, organizing them into logical batches: + + **Location methods** (for finding changes in XML): + - Section/heading numbers (e.g., "Section 3.2", "Article IV") + - Paragraph identifiers if numbered + - Grep patterns with unique surrounding text + - Document structure (e.g., "first paragraph", "signature block") + - **DO NOT use markdown line numbers** - they don't map to XML structure + + **Batch organization** (group 3-10 related changes per batch): + - By section: "Batch 1: Section 2 amendments", "Batch 2: Section 5 updates" + - By type: "Batch 1: Date corrections", "Batch 2: Party name changes" + - By complexity: Start with simple text replacements, then tackle complex structural changes + - Sequential: "Batch 1: Pages 1-3", "Batch 2: Pages 4-6" + +3. **Read documentation and unpack**: + - **MANDATORY - READ ENTIRE FILE**: Read [`ooxml.md`](ooxml.md) (~600 lines) completely from start to finish. **NEVER set any range limits when reading this file.** Pay special attention to the "Document Library" and "Tracked Change Patterns" sections. + - **Unpack the document**: `python ooxml/scripts/unpack.py ` + - **Note the suggested RSID**: The unpack script will suggest an RSID to use for your tracked changes. Copy this RSID for use in step 4b. + +4. **Implement changes in batches**: Group changes logically (by section, by type, or by proximity) and implement them together in a single script. This approach: + - Makes debugging easier (smaller batch = easier to isolate errors) + - Allows incremental progress + - Maintains efficiency (batch size of 3-10 changes works well) + + **Suggested batch groupings:** + - By document section (e.g., "Section 3 changes", "Definitions", "Termination clause") + - By change type (e.g., "Date changes", "Party name updates", "Legal term replacements") + - By proximity (e.g., "Changes on pages 1-3", "Changes in first half of document") + + For each batch of related changes: + + **a. Map text to XML**: Grep for text in `word/document.xml` to verify how text is split across `` elements. + + **b. Create and run script**: Use `get_node` to find nodes, implement changes, then `doc.save()`. See **"Document Library"** section in ooxml.md for patterns. + + **Note**: Always grep `word/document.xml` immediately before writing a script to get current line numbers and verify text content. Line numbers change after each script run. + +5. **Pack the document**: After all batches are complete, convert the unpacked directory back to .docx: + ```bash + python ooxml/scripts/pack.py unpacked reviewed-document.docx + ``` + +6. **Final verification**: Do a comprehensive check of the complete document: + - Convert final document to markdown: + ```bash + pandoc --track-changes=all reviewed-document.docx -o verification.md + ``` + - Verify ALL changes were applied correctly: + ```bash + grep "original phrase" verification.md # Should NOT find it + grep "replacement phrase" verification.md # Should find it + ``` + - Check that no unintended changes were introduced + + +## Converting Documents to Images + +To visually analyze Word documents, convert them to images using a two-step process: + +1. **Convert DOCX to PDF**: + ```bash + soffice --headless --convert-to pdf document.docx + ``` + +2. **Convert PDF pages to JPEG images**: + ```bash + pdftoppm -jpeg -r 150 document.pdf page + ``` + This creates files like `page-1.jpg`, `page-2.jpg`, etc. + +Options: +- `-r 150`: Sets resolution to 150 DPI (adjust for quality/size balance) +- `-jpeg`: Output JPEG format (use `-png` for PNG if preferred) +- `-f N`: First page to convert (e.g., `-f 2` starts from page 2) +- `-l N`: Last page to convert (e.g., `-l 5` stops at page 5) +- `page`: Prefix for output files + +Example for specific range: +```bash +pdftoppm -jpeg -r 150 -f 2 -l 5 document.pdf page # Converts only pages 2-5 +``` + +## Code Style Guidelines +**IMPORTANT**: When generating code for DOCX operations: +- Write concise code +- Avoid verbose variable names and redundant operations +- Avoid unnecessary print statements + +## Dependencies + +Required dependencies (install if not available): + +- **pandoc**: `sudo apt-get install pandoc` (for text extraction) +- **docx**: `npm install -g docx` (for creating new documents) +- **LibreOffice**: `sudo apt-get install libreoffice` (for PDF conversion) +- **Poppler**: `sudo apt-get install poppler-utils` (for pdftoppm to convert PDF to images) +- **defusedxml**: `pip install defusedxml` (for secure XML parsing) \ No newline at end of file diff --git a/skills/docx/docx-js.md b/skills/docx/docx-js.md new file mode 100644 index 0000000..c6d7b2d --- /dev/null +++ b/skills/docx/docx-js.md @@ -0,0 +1,350 @@ +# DOCX Library Tutorial + +Generate .docx files with JavaScript/TypeScript. + +**Important: Read this entire document before starting.** Critical formatting rules and common pitfalls are covered throughout - skipping sections may result in corrupted files or rendering issues. + +## Setup +Assumes docx is already installed globally +If not installed: `npm install -g docx` + +```javascript +const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, ImageRun, Media, + Header, Footer, AlignmentType, PageOrientation, LevelFormat, ExternalHyperlink, + InternalHyperlink, TableOfContents, HeadingLevel, BorderStyle, WidthType, TabStopType, + TabStopPosition, UnderlineType, ShadingType, VerticalAlign, SymbolRun, PageNumber, + FootnoteReferenceRun, Footnote, PageBreak } = require('docx'); + +// Create & Save +const doc = new Document({ sections: [{ children: [/* content */] }] }); +Packer.toBuffer(doc).then(buffer => fs.writeFileSync("doc.docx", buffer)); // Node.js +Packer.toBlob(doc).then(blob => { /* download logic */ }); // Browser +``` + +## Text & Formatting +```javascript +// IMPORTANT: Never use \n for line breaks - always use separate Paragraph elements +// ❌ WRONG: new TextRun("Line 1\nLine 2") +// ✅ CORRECT: new Paragraph({ children: [new TextRun("Line 1")] }), new Paragraph({ children: [new TextRun("Line 2")] }) + +// Basic text with all formatting options +new Paragraph({ + alignment: AlignmentType.CENTER, + spacing: { before: 200, after: 200 }, + indent: { left: 720, right: 720 }, + children: [ + new TextRun({ text: "Bold", bold: true }), + new TextRun({ text: "Italic", italics: true }), + new TextRun({ text: "Underlined", underline: { type: UnderlineType.DOUBLE, color: "FF0000" } }), + new TextRun({ text: "Colored", color: "FF0000", size: 28, font: "Arial" }), // Arial default + new TextRun({ text: "Highlighted", highlight: "yellow" }), + new TextRun({ text: "Strikethrough", strike: true }), + new TextRun({ text: "x2", superScript: true }), + new TextRun({ text: "H2O", subScript: true }), + new TextRun({ text: "SMALL CAPS", smallCaps: true }), + new SymbolRun({ char: "2022", font: "Symbol" }), // Bullet • + new SymbolRun({ char: "00A9", font: "Arial" }) // Copyright © - Arial for symbols + ] +}) +``` + +## Styles & Professional Formatting + +```javascript +const doc = new Document({ + styles: { + default: { document: { run: { font: "Arial", size: 24 } } }, // 12pt default + paragraphStyles: [ + // Document title style - override built-in Title style + { id: "Title", name: "Title", basedOn: "Normal", + run: { size: 56, bold: true, color: "000000", font: "Arial" }, + paragraph: { spacing: { before: 240, after: 120 }, alignment: AlignmentType.CENTER } }, + // IMPORTANT: Override built-in heading styles by using their exact IDs + { id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal", quickFormat: true, + run: { size: 32, bold: true, color: "000000", font: "Arial" }, // 16pt + paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 } }, // Required for TOC + { id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal", quickFormat: true, + run: { size: 28, bold: true, color: "000000", font: "Arial" }, // 14pt + paragraph: { spacing: { before: 180, after: 180 }, outlineLevel: 1 } }, + // Custom styles use your own IDs + { id: "myStyle", name: "My Style", basedOn: "Normal", + run: { size: 28, bold: true, color: "000000" }, + paragraph: { spacing: { after: 120 }, alignment: AlignmentType.CENTER } } + ], + characterStyles: [{ id: "myCharStyle", name: "My Char Style", + run: { color: "FF0000", bold: true, underline: { type: UnderlineType.SINGLE } } }] + }, + sections: [{ + properties: { page: { margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } } }, + children: [ + new Paragraph({ heading: HeadingLevel.TITLE, children: [new TextRun("Document Title")] }), // Uses overridden Title style + new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun("Heading 1")] }), // Uses overridden Heading1 style + new Paragraph({ style: "myStyle", children: [new TextRun("Custom paragraph style")] }), + new Paragraph({ children: [ + new TextRun("Normal with "), + new TextRun({ text: "custom char style", style: "myCharStyle" }) + ]}) + ] + }] +}); +``` + +**Professional Font Combinations:** +- **Arial (Headers) + Arial (Body)** - Most universally supported, clean and professional +- **Times New Roman (Headers) + Arial (Body)** - Classic serif headers with modern sans-serif body +- **Georgia (Headers) + Verdana (Body)** - Optimized for screen reading, elegant contrast + +**Key Styling Principles:** +- **Override built-in styles**: Use exact IDs like "Heading1", "Heading2", "Heading3" to override Word's built-in heading styles +- **HeadingLevel constants**: `HeadingLevel.HEADING_1` uses "Heading1" style, `HeadingLevel.HEADING_2` uses "Heading2" style, etc. +- **Include outlineLevel**: Set `outlineLevel: 0` for H1, `outlineLevel: 1` for H2, etc. to ensure TOC works correctly +- **Use custom styles** instead of inline formatting for consistency +- **Set a default font** using `styles.default.document.run.font` - Arial is universally supported +- **Establish visual hierarchy** with different font sizes (titles > headers > body) +- **Add proper spacing** with `before` and `after` paragraph spacing +- **Use colors sparingly**: Default to black (000000) and shades of gray for titles and headings (heading 1, heading 2, etc.) +- **Set consistent margins** (1440 = 1 inch is standard) + + +## Lists (ALWAYS USE PROPER LISTS - NEVER USE UNICODE BULLETS) +```javascript +// Bullets - ALWAYS use the numbering config, NOT unicode symbols +// CRITICAL: Use LevelFormat.BULLET constant, NOT the string "bullet" +const doc = new Document({ + numbering: { + config: [ + { reference: "bullet-list", + levels: [{ level: 0, format: LevelFormat.BULLET, text: "•", alignment: AlignmentType.LEFT, + style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] }, + { reference: "first-numbered-list", + levels: [{ level: 0, format: LevelFormat.DECIMAL, text: "%1.", alignment: AlignmentType.LEFT, + style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] }, + { reference: "second-numbered-list", // Different reference = restarts at 1 + levels: [{ level: 0, format: LevelFormat.DECIMAL, text: "%1.", alignment: AlignmentType.LEFT, + style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] } + ] + }, + sections: [{ + children: [ + // Bullet list items + new Paragraph({ numbering: { reference: "bullet-list", level: 0 }, + children: [new TextRun("First bullet point")] }), + new Paragraph({ numbering: { reference: "bullet-list", level: 0 }, + children: [new TextRun("Second bullet point")] }), + // Numbered list items + new Paragraph({ numbering: { reference: "first-numbered-list", level: 0 }, + children: [new TextRun("First numbered item")] }), + new Paragraph({ numbering: { reference: "first-numbered-list", level: 0 }, + children: [new TextRun("Second numbered item")] }), + // ⚠️ CRITICAL: Different reference = INDEPENDENT list that restarts at 1 + // Same reference = CONTINUES previous numbering + new Paragraph({ numbering: { reference: "second-numbered-list", level: 0 }, + children: [new TextRun("Starts at 1 again (because different reference)")] }) + ] + }] +}); + +// ⚠️ CRITICAL NUMBERING RULE: Each reference creates an INDEPENDENT numbered list +// - Same reference = continues numbering (1, 2, 3... then 4, 5, 6...) +// - Different reference = restarts at 1 (1, 2, 3... then 1, 2, 3...) +// Use unique reference names for each separate numbered section! + +// ⚠️ CRITICAL: NEVER use unicode bullets - they create fake lists that don't work properly +// new TextRun("• Item") // WRONG +// new SymbolRun({ char: "2022" }) // WRONG +// ✅ ALWAYS use numbering config with LevelFormat.BULLET for real Word lists +``` + +## Tables +```javascript +// Complete table with margins, borders, headers, and bullet points +const tableBorder = { style: BorderStyle.SINGLE, size: 1, color: "CCCCCC" }; +const cellBorders = { top: tableBorder, bottom: tableBorder, left: tableBorder, right: tableBorder }; + +new Table({ + columnWidths: [4680, 4680], // ⚠️ CRITICAL: Set column widths at table level - values in DXA (twentieths of a point) + margins: { top: 100, bottom: 100, left: 180, right: 180 }, // Set once for all cells + rows: [ + new TableRow({ + tableHeader: true, + children: [ + new TableCell({ + borders: cellBorders, + width: { size: 4680, type: WidthType.DXA }, // ALSO set width on each cell + // ⚠️ CRITICAL: Always use ShadingType.CLEAR to prevent black backgrounds in Word. + shading: { fill: "D5E8F0", type: ShadingType.CLEAR }, + verticalAlign: VerticalAlign.CENTER, + children: [new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ text: "Header", bold: true, size: 22 })] + })] + }), + new TableCell({ + borders: cellBorders, + width: { size: 4680, type: WidthType.DXA }, // ALSO set width on each cell + shading: { fill: "D5E8F0", type: ShadingType.CLEAR }, + children: [new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ text: "Bullet Points", bold: true, size: 22 })] + })] + }) + ] + }), + new TableRow({ + children: [ + new TableCell({ + borders: cellBorders, + width: { size: 4680, type: WidthType.DXA }, // ALSO set width on each cell + children: [new Paragraph({ children: [new TextRun("Regular data")] })] + }), + new TableCell({ + borders: cellBorders, + width: { size: 4680, type: WidthType.DXA }, // ALSO set width on each cell + children: [ + new Paragraph({ + numbering: { reference: "bullet-list", level: 0 }, + children: [new TextRun("First bullet point")] + }), + new Paragraph({ + numbering: { reference: "bullet-list", level: 0 }, + children: [new TextRun("Second bullet point")] + }) + ] + }) + ] + }) + ] +}) +``` + +**IMPORTANT: Table Width & Borders** +- Use BOTH `columnWidths: [width1, width2, ...]` array AND `width: { size: X, type: WidthType.DXA }` on each cell +- Values in DXA (twentieths of a point): 1440 = 1 inch, Letter usable width = 9360 DXA (with 1" margins) +- Apply borders to individual `TableCell` elements, NOT the `Table` itself + +**Precomputed Column Widths (Letter size with 1" margins = 9360 DXA total):** +- **2 columns:** `columnWidths: [4680, 4680]` (equal width) +- **3 columns:** `columnWidths: [3120, 3120, 3120]` (equal width) + +## Links & Navigation +```javascript +// TOC (requires headings) - CRITICAL: Use HeadingLevel only, NOT custom styles +// ❌ WRONG: new Paragraph({ heading: HeadingLevel.HEADING_1, style: "customHeader", children: [new TextRun("Title")] }) +// ✅ CORRECT: new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun("Title")] }) +new TableOfContents("Table of Contents", { hyperlink: true, headingStyleRange: "1-3" }), + +// External link +new Paragraph({ + children: [new ExternalHyperlink({ + children: [new TextRun({ text: "Google", style: "Hyperlink" })], + link: "https://www.google.com" + })] +}), + +// Internal link & bookmark +new Paragraph({ + children: [new InternalHyperlink({ + children: [new TextRun({ text: "Go to Section", style: "Hyperlink" })], + anchor: "section1" + })] +}), +new Paragraph({ + children: [new TextRun("Section Content")], + bookmark: { id: "section1", name: "section1" } +}), +``` + +## Images & Media +```javascript +// Basic image with sizing & positioning +// CRITICAL: Always specify 'type' parameter - it's REQUIRED for ImageRun +new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new ImageRun({ + type: "png", // NEW REQUIREMENT: Must specify image type (png, jpg, jpeg, gif, bmp, svg) + data: fs.readFileSync("image.png"), + transformation: { width: 200, height: 150, rotation: 0 }, // rotation in degrees + altText: { title: "Logo", description: "Company logo", name: "Name" } // IMPORTANT: All three fields are required + })] +}) +``` + +## Page Breaks +```javascript +// Manual page break +new Paragraph({ children: [new PageBreak()] }), + +// Page break before paragraph +new Paragraph({ + pageBreakBefore: true, + children: [new TextRun("This starts on a new page")] +}) + +// ⚠️ CRITICAL: NEVER use PageBreak standalone - it will create invalid XML that Word cannot open +// ❌ WRONG: new PageBreak() +// ✅ CORRECT: new Paragraph({ children: [new PageBreak()] }) +``` + +## Headers/Footers & Page Setup +```javascript +const doc = new Document({ + sections: [{ + properties: { + page: { + margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 }, // 1440 = 1 inch + size: { orientation: PageOrientation.LANDSCAPE }, + pageNumbers: { start: 1, formatType: "decimal" } // "upperRoman", "lowerRoman", "upperLetter", "lowerLetter" + } + }, + headers: { + default: new Header({ children: [new Paragraph({ + alignment: AlignmentType.RIGHT, + children: [new TextRun("Header Text")] + })] }) + }, + footers: { + default: new Footer({ children: [new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun("Page "), new TextRun({ children: [PageNumber.CURRENT] }), new TextRun(" of "), new TextRun({ children: [PageNumber.TOTAL_PAGES] })] + })] }) + }, + children: [/* content */] + }] +}); +``` + +## Tabs +```javascript +new Paragraph({ + tabStops: [ + { type: TabStopType.LEFT, position: TabStopPosition.MAX / 4 }, + { type: TabStopType.CENTER, position: TabStopPosition.MAX / 2 }, + { type: TabStopType.RIGHT, position: TabStopPosition.MAX * 3 / 4 } + ], + children: [new TextRun("Left\tCenter\tRight")] +}) +``` + +## Constants & Quick Reference +- **Underlines:** `SINGLE`, `DOUBLE`, `WAVY`, `DASH` +- **Borders:** `SINGLE`, `DOUBLE`, `DASHED`, `DOTTED` +- **Numbering:** `DECIMAL` (1,2,3), `UPPER_ROMAN` (I,II,III), `LOWER_LETTER` (a,b,c) +- **Tabs:** `LEFT`, `CENTER`, `RIGHT`, `DECIMAL` +- **Symbols:** `"2022"` (•), `"00A9"` (©), `"00AE"` (®), `"2122"` (™), `"00B0"` (°), `"F070"` (✓), `"F0FC"` (✗) + +## Critical Issues & Common Mistakes +- **CRITICAL: PageBreak must ALWAYS be inside a Paragraph** - standalone PageBreak creates invalid XML that Word cannot open +- **ALWAYS use ShadingType.CLEAR for table cell shading** - Never use ShadingType.SOLID (causes black background). +- Measurements in DXA (1440 = 1 inch) | Each table cell needs ≥1 Paragraph | TOC requires HeadingLevel styles only +- **ALWAYS use custom styles** with Arial font for professional appearance and proper visual hierarchy +- **ALWAYS set a default font** using `styles.default.document.run.font` - Arial recommended +- **ALWAYS use columnWidths array for tables** + individual cell widths for compatibility +- **NEVER use unicode symbols for bullets** - always use proper numbering configuration with `LevelFormat.BULLET` constant (NOT the string "bullet") +- **NEVER use \n for line breaks anywhere** - always use separate Paragraph elements for each line +- **ALWAYS use TextRun objects within Paragraph children** - never use text property directly on Paragraph +- **CRITICAL for images**: ImageRun REQUIRES `type` parameter - always specify "png", "jpg", "jpeg", "gif", "bmp", or "svg" +- **CRITICAL for bullets**: Must use `LevelFormat.BULLET` constant, not string "bullet", and include `text: "•"` for the bullet character +- **CRITICAL for numbering**: Each numbering reference creates an INDEPENDENT list. Same reference = continues numbering (1,2,3 then 4,5,6). Different reference = restarts at 1 (1,2,3 then 1,2,3). Use unique reference names for each separate numbered section! +- **CRITICAL for TOC**: When using TableOfContents, headings must use HeadingLevel ONLY - do NOT add custom styles to heading paragraphs or TOC will break +- **Tables**: Set `columnWidths` array + individual cell widths, apply borders to cells not table +- **Set table margins at TABLE level** for consistent cell padding (avoids repetition per cell) \ No newline at end of file diff --git a/skills/docx/ooxml.md b/skills/docx/ooxml.md new file mode 100644 index 0000000..7677e7b --- /dev/null +++ b/skills/docx/ooxml.md @@ -0,0 +1,610 @@ +# Office Open XML Technical Reference + +**Important: Read this entire document before starting.** This document covers: +- [Technical Guidelines](#technical-guidelines) - Schema compliance rules and validation requirements +- [Document Content Patterns](#document-content-patterns) - XML patterns for headings, lists, tables, formatting, etc. +- [Document Library (Python)](#document-library-python) - Recommended approach for OOXML manipulation with automatic infrastructure setup +- [Tracked Changes (Redlining)](#tracked-changes-redlining) - XML patterns for implementing tracked changes + +## Technical Guidelines + +### Schema Compliance +- **Element ordering in ``**: ``, ``, ``, ``, `` +- **Whitespace**: Add `xml:space='preserve'` to `` elements with leading/trailing spaces +- **Unicode**: Escape characters in ASCII content: `"` becomes `“` + - **Character encoding reference**: Curly quotes `""` become `“”`, apostrophe `'` becomes `’`, em-dash `—` becomes `—` +- **Tracked changes**: Use `` and `` tags with `w:author="Claude"` outside `` elements + - **Critical**: `` closes with ``, `` closes with `` - never mix + - **RSIDs must be 8-digit hex**: Use values like `00AB1234` (only 0-9, A-F characters) + - **trackRevisions placement**: Add `` after `` in settings.xml +- **Images**: Add to `word/media/`, reference in `document.xml`, set dimensions to prevent overflow + +## Document Content Patterns + +### Basic Structure +```xml + + Text content + +``` + +### Headings and Styles +```xml + + + + + + Document Title + + + + + Section Heading + +``` + +### Text Formatting +```xml + +Bold + +Italic + +Underlined + +Highlighted +``` + +### Lists +```xml + + + + + + + + First item + + + + + + + + + + New list item 1 + + + + + + + + + + + Bullet item + +``` + +### Tables +```xml + + + + + + + + + + + + Cell 1 + + + + Cell 2 + + + +``` + +### Layout +```xml + + + + + + + + + + + + New Section Title + + + + + + + + + + Centered text + + + + + + + + Monospace text + + + + + + + This text is Courier New + + and this text uses default font + +``` + +## File Updates + +When adding content, update these files: + +**`word/_rels/document.xml.rels`:** +```xml + + +``` + +**`[Content_Types].xml`:** +```xml + + +``` + +### Images +**CRITICAL**: Calculate dimensions to prevent page overflow and maintain aspect ratio. + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +### Links (Hyperlinks) + +**IMPORTANT**: All hyperlinks (both internal and external) require the Hyperlink style to be defined in styles.xml. Without this style, links will look like regular text instead of blue underlined clickable links. + +**External Links:** +```xml + + + + + Link Text + + + + + +``` + +**Internal Links:** + +```xml + + + + + Link Text + + + + + +Target content + +``` + +**Hyperlink Style (required in styles.xml):** +```xml + + + + + + + + + + +``` + +## Document Library (Python) + +Use the Document class from `scripts/document.py` for all tracked changes and comments. It automatically handles infrastructure setup (people.xml, RSIDs, settings.xml, comment files, relationships, content types). Only use direct XML manipulation for complex scenarios not supported by the library. + +**Working with Unicode and Entities:** +- **Searching**: Both entity notation and Unicode characters work - `contains="“Company"` and `contains="\u201cCompany"` find the same text +- **Replacing**: Use either entities (`“`) or Unicode (`\u201c`) - both work and will be converted appropriately based on the file's encoding (ascii → entities, utf-8 → Unicode) + +### Initialization + +**Find the docx skill root** (directory containing `scripts/` and `ooxml/`): +```bash +# Search for document.py to locate the skill root +# Note: /mnt/skills is used here as an example; check your context for the actual location +find /mnt/skills -name "document.py" -path "*/docx/scripts/*" 2>/dev/null | head -1 +# Example output: /mnt/skills/docx/scripts/document.py +# Skill root is: /mnt/skills/docx +``` + +**Run your script with PYTHONPATH** set to the docx skill root: +```bash +PYTHONPATH=/mnt/skills/docx python your_script.py +``` + +**In your script**, import from the skill root: +```python +from scripts.document import Document, DocxXMLEditor + +# Basic initialization (automatically creates temp copy and sets up infrastructure) +doc = Document('unpacked') + +# Customize author and initials +doc = Document('unpacked', author="John Doe", initials="JD") + +# Enable track revisions mode +doc = Document('unpacked', track_revisions=True) + +# Specify custom RSID (auto-generated if not provided) +doc = Document('unpacked', rsid="07DC5ECB") +``` + +### Creating Tracked Changes + +**CRITICAL**: Only mark text that actually changes. Keep ALL unchanged text outside ``/`` tags. Marking unchanged text makes edits unprofessional and harder to review. + +**Attribute Handling**: The Document class auto-injects attributes (w:id, w:date, w:rsidR, w:rsidDel, w16du:dateUtc, xml:space) into new elements. When preserving unchanged text from the original document, copy the original `` element with its existing attributes to maintain document integrity. + +**Method Selection Guide**: +- **Adding your own changes to regular text**: Use `replace_node()` with ``/`` tags, or `suggest_deletion()` for removing entire `` or `` elements +- **Partially modifying another author's tracked change**: Use `replace_node()` to nest your changes inside their ``/`` +- **Completely rejecting another author's insertion**: Use `revert_insertion()` on the `` element (NOT `suggest_deletion()`) +- **Completely rejecting another author's deletion**: Use `revert_deletion()` on the `` element to restore deleted content using tracked changes + +```python +# Minimal edit - change one word: "The report is monthly" → "The report is quarterly" +# Original: The report is monthly +node = doc["word/document.xml"].get_node(tag="w:r", contains="The report is monthly") +rpr = tags[0].toxml() if (tags := node.getElementsByTagName("w:rPr")) else "" +replacement = f'{rpr}The report is {rpr}monthly{rpr}quarterly' +doc["word/document.xml"].replace_node(node, replacement) + +# Minimal edit - change number: "within 30 days" → "within 45 days" +# Original: within 30 days +node = doc["word/document.xml"].get_node(tag="w:r", contains="within 30 days") +rpr = tags[0].toxml() if (tags := node.getElementsByTagName("w:rPr")) else "" +replacement = f'{rpr}within {rpr}30{rpr}45{rpr} days' +doc["word/document.xml"].replace_node(node, replacement) + +# Complete replacement - preserve formatting even when replacing all text +node = doc["word/document.xml"].get_node(tag="w:r", contains="apple") +rpr = tags[0].toxml() if (tags := node.getElementsByTagName("w:rPr")) else "" +replacement = f'{rpr}apple{rpr}banana orange' +doc["word/document.xml"].replace_node(node, replacement) + +# Insert new content (no attributes needed - auto-injected) +node = doc["word/document.xml"].get_node(tag="w:r", contains="existing text") +doc["word/document.xml"].insert_after(node, 'new text') + +# Partially delete another author's insertion +# Original: quarterly financial report +# Goal: Delete only "financial" to make it "quarterly report" +node = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id": "5"}) +# IMPORTANT: Preserve w:author="Jane Smith" on the outer to maintain authorship +replacement = ''' + quarterly + financial + report +''' +doc["word/document.xml"].replace_node(node, replacement) + +# Change part of another author's insertion +# Original: in silence, safe and sound +# Goal: Change "safe and sound" to "soft and unbound" +node = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id": "8"}) +replacement = f''' + in silence, + + + soft and unbound + + + safe and sound +''' +doc["word/document.xml"].replace_node(node, replacement) + +# Delete entire run (use only when deleting all content; use replace_node for partial deletions) +node = doc["word/document.xml"].get_node(tag="w:r", contains="text to delete") +doc["word/document.xml"].suggest_deletion(node) + +# Delete entire paragraph (in-place, handles both regular and numbered list paragraphs) +para = doc["word/document.xml"].get_node(tag="w:p", contains="paragraph to delete") +doc["word/document.xml"].suggest_deletion(para) + +# Add new numbered list item +target_para = doc["word/document.xml"].get_node(tag="w:p", contains="existing list item") +pPr = tags[0].toxml() if (tags := target_para.getElementsByTagName("w:pPr")) else "" +new_item = f'{pPr}New item' +tracked_para = DocxXMLEditor.suggest_paragraph(new_item) +doc["word/document.xml"].insert_after(target_para, tracked_para) +# Optional: add spacing paragraph before content for better visual separation +# spacing = DocxXMLEditor.suggest_paragraph('') +# doc["word/document.xml"].insert_after(target_para, spacing + tracked_para) +``` + +### Adding Comments + +```python +# Add comment spanning two existing tracked changes +# Note: w:id is auto-generated. Only search by w:id if you know it from XML inspection +start_node = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "1"}) +end_node = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id": "2"}) +doc.add_comment(start=start_node, end=end_node, text="Explanation of this change") + +# Add comment on a paragraph +para = doc["word/document.xml"].get_node(tag="w:p", contains="paragraph text") +doc.add_comment(start=para, end=para, text="Comment on this paragraph") + +# Add comment on newly created tracked change +# First create the tracked change +node = doc["word/document.xml"].get_node(tag="w:r", contains="old") +new_nodes = doc["word/document.xml"].replace_node( + node, + 'oldnew' +) +# Then add comment on the newly created elements +# new_nodes[0] is the , new_nodes[1] is the +doc.add_comment(start=new_nodes[0], end=new_nodes[1], text="Changed old to new per requirements") + +# Reply to existing comment +doc.reply_to_comment(parent_comment_id=0, text="I agree with this change") +``` + +### Rejecting Tracked Changes + +**IMPORTANT**: Use `revert_insertion()` to reject insertions and `revert_deletion()` to restore deletions using tracked changes. Use `suggest_deletion()` only for regular unmarked content. + +```python +# Reject insertion (wraps it in deletion) +# Use this when another author inserted text that you want to delete +ins = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id": "5"}) +nodes = doc["word/document.xml"].revert_insertion(ins) # Returns [ins] + +# Reject deletion (creates insertion to restore deleted content) +# Use this when another author deleted text that you want to restore +del_elem = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "3"}) +nodes = doc["word/document.xml"].revert_deletion(del_elem) # Returns [del_elem, new_ins] + +# Reject all insertions in a paragraph +para = doc["word/document.xml"].get_node(tag="w:p", contains="paragraph text") +nodes = doc["word/document.xml"].revert_insertion(para) # Returns [para] + +# Reject all deletions in a paragraph +para = doc["word/document.xml"].get_node(tag="w:p", contains="paragraph text") +nodes = doc["word/document.xml"].revert_deletion(para) # Returns [para] +``` + +### Inserting Images + +**CRITICAL**: The Document class works with a temporary copy at `doc.unpacked_path`. Always copy images to this temp directory, not the original unpacked folder. + +```python +from PIL import Image +import shutil, os + +# Initialize document first +doc = Document('unpacked') + +# Copy image and calculate full-width dimensions with aspect ratio +media_dir = os.path.join(doc.unpacked_path, 'word/media') +os.makedirs(media_dir, exist_ok=True) +shutil.copy('image.png', os.path.join(media_dir, 'image1.png')) +img = Image.open(os.path.join(media_dir, 'image1.png')) +width_emus = int(6.5 * 914400) # 6.5" usable width, 914400 EMUs/inch +height_emus = int(width_emus * img.size[1] / img.size[0]) + +# Add relationship and content type +rels_editor = doc['word/_rels/document.xml.rels'] +next_rid = rels_editor.get_next_rid() +rels_editor.append_to(rels_editor.dom.documentElement, + f'') +doc['[Content_Types].xml'].append_to(doc['[Content_Types].xml'].dom.documentElement, + '') + +# Insert image +node = doc["word/document.xml"].get_node(tag="w:p", line_number=100) +doc["word/document.xml"].insert_after(node, f''' + + + + + + + + + + + + + + + + + +''') +``` + +### Getting Nodes + +```python +# By text content +node = doc["word/document.xml"].get_node(tag="w:p", contains="specific text") + +# By line range +para = doc["word/document.xml"].get_node(tag="w:p", line_number=range(100, 150)) + +# By attributes +node = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "1"}) + +# By exact line number (must be line number where tag opens) +para = doc["word/document.xml"].get_node(tag="w:p", line_number=42) + +# Combine filters +node = doc["word/document.xml"].get_node(tag="w:r", line_number=range(40, 60), contains="text") + +# Disambiguate when text appears multiple times - add line_number range +node = doc["word/document.xml"].get_node(tag="w:r", contains="Section", line_number=range(2400, 2500)) +``` + +### Saving + +```python +# Save with automatic validation (copies back to original directory) +doc.save() # Validates by default, raises error if validation fails + +# Save to different location +doc.save('modified-unpacked') + +# Skip validation (debugging only - needing this in production indicates XML issues) +doc.save(validate=False) +``` + +### Direct DOM Manipulation + +For complex scenarios not covered by the library: + +```python +# Access any XML file +editor = doc["word/document.xml"] +editor = doc["word/comments.xml"] + +# Direct DOM access (defusedxml.minidom.Document) +node = doc["word/document.xml"].get_node(tag="w:p", line_number=5) +parent = node.parentNode +parent.removeChild(node) +parent.appendChild(node) # Move to end + +# General document manipulation (without tracked changes) +old_node = doc["word/document.xml"].get_node(tag="w:p", contains="original text") +doc["word/document.xml"].replace_node(old_node, "replacement text") + +# Multiple insertions - use return value to maintain order +node = doc["word/document.xml"].get_node(tag="w:r", line_number=100) +nodes = doc["word/document.xml"].insert_after(node, "A") +nodes = doc["word/document.xml"].insert_after(nodes[-1], "B") +nodes = doc["word/document.xml"].insert_after(nodes[-1], "C") +# Results in: original_node, A, B, C +``` + +## Tracked Changes (Redlining) + +**Use the Document class above for all tracked changes.** The patterns below are for reference when constructing replacement XML strings. + +### Validation Rules +The validator checks that the document text matches the original after reverting Claude's changes. This means: +- **NEVER modify text inside another author's `` or `` tags** +- **ALWAYS use nested deletions** to remove another author's insertions +- **Every edit must be properly tracked** with `` or `` tags + +### Tracked Change Patterns + +**CRITICAL RULES**: +1. Never modify the content inside another author's tracked changes. Always use nested deletions. +2. **XML Structure**: Always place `` and `` at paragraph level containing complete `` elements. Never nest inside `` elements - this creates invalid XML that breaks document processing. + +**Text Insertion:** +```xml + + + inserted text + + +``` + +**Text Deletion:** +```xml + + + deleted text + + +``` + +**Deleting Another Author's Insertion (MUST use nested structure):** +```xml + + + + monthly + + + + weekly + +``` + +**Restoring Another Author's Deletion:** +```xml + + + within 30 days + + + within 30 days + +``` \ No newline at end of file diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd new file mode 100644 index 0000000..6454ef9 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd @@ -0,0 +1,1499 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd new file mode 100644 index 0000000..afa4f46 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd new file mode 100644 index 0000000..64e66b8 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd @@ -0,0 +1,1085 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd new file mode 100644 index 0000000..687eea8 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd @@ -0,0 +1,11 @@ + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd new file mode 100644 index 0000000..6ac81b0 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd @@ -0,0 +1,3081 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd new file mode 100644 index 0000000..1dbf051 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd new file mode 100644 index 0000000..f1af17d --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd new file mode 100644 index 0000000..0a185ab --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd @@ -0,0 +1,287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd new file mode 100644 index 0000000..14ef488 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd @@ -0,0 +1,1676 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd new file mode 100644 index 0000000..c20f3bf --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd new file mode 100644 index 0000000..ac60252 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd new file mode 100644 index 0000000..424b8ba --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd new file mode 100644 index 0000000..2bddce2 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd new file mode 100644 index 0000000..8a8c18b --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd new file mode 100644 index 0000000..5c42706 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd new file mode 100644 index 0000000..853c341 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd new file mode 100644 index 0000000..da835ee --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd new file mode 100644 index 0000000..87ad265 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd @@ -0,0 +1,582 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd new file mode 100644 index 0000000..9e86f1b --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd new file mode 100644 index 0000000..d0be42e --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd @@ -0,0 +1,4439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd new file mode 100644 index 0000000..8821dd1 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd @@ -0,0 +1,570 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd new file mode 100644 index 0000000..ca2575c --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd @@ -0,0 +1,509 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd new file mode 100644 index 0000000..dd079e6 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd new file mode 100644 index 0000000..3dd6cf6 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd new file mode 100644 index 0000000..f1041e3 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd new file mode 100644 index 0000000..9c5b7a6 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd @@ -0,0 +1,3646 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd new file mode 100644 index 0000000..0f13678 --- /dev/null +++ b/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd @@ -0,0 +1,116 @@ + + + + + + See http://www.w3.org/XML/1998/namespace.html and + http://www.w3.org/TR/REC-xml for information about this namespace. + + This schema document describes the XML namespace, in a form + suitable for import by other schema documents. + + Note that local names in this namespace are intended to be defined + only by the World Wide Web Consortium or its subgroups. The + following names are currently defined in this namespace and should + not be used with conflicting semantics by any Working Group, + specification, or document instance: + + base (as an attribute name): denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification. + + lang (as an attribute name): denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification. + + space (as an attribute name): denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification. + + Father (in any context at all): denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: + + In appreciation for his vision, leadership and dedication + the W3C XML Plenary on this 10th day of February, 2000 + reserves for Jon Bosak in perpetuity the XML name + xml:Father + + + + + This schema defines attributes and an attribute group + suitable for use by + schemas wishing to allow xml:base, xml:lang or xml:space attributes + on elements they define. + + To enable this, such a schema must import this schema + for the XML namespace, e.g. as follows: + <schema . . .> + . . . + <import namespace="http://www.w3.org/XML/1998/namespace" + schemaLocation="http://www.w3.org/2001/03/xml.xsd"/> + + Subsequently, qualified reference to any of the attributes + or the group defined below will have the desired effect, e.g. + + <type . . .> + . . . + <attributeGroup ref="xml:specialAttrs"/> + + will define a type which will schema-validate an instance + element with any of those attributes + + + + In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + http://www.w3.org/2001/03/xml.xsd. + At the date of issue it can also be found at + http://www.w3.org/2001/xml.xsd. + The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML Schema + itself. In other words, if the XML Schema namespace changes, the version + of this document at + http://www.w3.org/2001/xml.xsd will change + accordingly; the version at + http://www.w3.org/2001/03/xml.xsd will not change. + + + + + + In due course, we should install the relevant ISO 2- and 3-letter + codes as the enumerated possible values . . . + + + + + + + + + + + + + + + See http://www.w3.org/TR/xmlbase/ for + information about this attribute. + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd b/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd new file mode 100644 index 0000000..a6de9d2 --- /dev/null +++ b/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd b/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd new file mode 100644 index 0000000..10e978b --- /dev/null +++ b/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd b/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd new file mode 100644 index 0000000..4248bf7 --- /dev/null +++ b/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd b/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd new file mode 100644 index 0000000..5649746 --- /dev/null +++ b/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/mce/mc.xsd b/skills/docx/ooxml/schemas/mce/mc.xsd new file mode 100644 index 0000000..ef72545 --- /dev/null +++ b/skills/docx/ooxml/schemas/mce/mc.xsd @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd b/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd new file mode 100644 index 0000000..f65f777 --- /dev/null +++ b/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd @@ -0,0 +1,560 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd b/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd new file mode 100644 index 0000000..6b00755 --- /dev/null +++ b/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd b/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd new file mode 100644 index 0000000..f321d33 --- /dev/null +++ b/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd b/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd new file mode 100644 index 0000000..364c6a9 --- /dev/null +++ b/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd b/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd new file mode 100644 index 0000000..fed9d15 --- /dev/null +++ b/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd b/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd new file mode 100644 index 0000000..680cf15 --- /dev/null +++ b/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd @@ -0,0 +1,4 @@ + + + + diff --git a/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd b/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd new file mode 100644 index 0000000..89ada90 --- /dev/null +++ b/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/skills/docx/ooxml/scripts/pack.py b/skills/docx/ooxml/scripts/pack.py new file mode 100755 index 0000000..68bc088 --- /dev/null +++ b/skills/docx/ooxml/scripts/pack.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +""" +Tool to pack a directory into a .docx, .pptx, or .xlsx file with XML formatting undone. + +Example usage: + python pack.py [--force] +""" + +import argparse +import shutil +import subprocess +import sys +import tempfile +import defusedxml.minidom +import zipfile +from pathlib import Path + + +def main(): + parser = argparse.ArgumentParser(description="Pack a directory into an Office file") + parser.add_argument("input_directory", help="Unpacked Office document directory") + parser.add_argument("output_file", help="Output Office file (.docx/.pptx/.xlsx)") + parser.add_argument("--force", action="store_true", help="Skip validation") + args = parser.parse_args() + + try: + success = pack_document( + args.input_directory, args.output_file, validate=not args.force + ) + + # Show warning if validation was skipped + if args.force: + print("Warning: Skipped validation, file may be corrupt", file=sys.stderr) + # Exit with error if validation failed + elif not success: + print("Contents would produce a corrupt file.", file=sys.stderr) + print("Please validate XML before repacking.", file=sys.stderr) + print("Use --force to skip validation and pack anyway.", file=sys.stderr) + sys.exit(1) + + except ValueError as e: + sys.exit(f"Error: {e}") + + +def pack_document(input_dir, output_file, validate=False): + """Pack a directory into an Office file (.docx/.pptx/.xlsx). + + Args: + input_dir: Path to unpacked Office document directory + output_file: Path to output Office file + validate: If True, validates with soffice (default: False) + + Returns: + bool: True if successful, False if validation failed + """ + input_dir = Path(input_dir) + output_file = Path(output_file) + + if not input_dir.is_dir(): + raise ValueError(f"{input_dir} is not a directory") + if output_file.suffix.lower() not in {".docx", ".pptx", ".xlsx"}: + raise ValueError(f"{output_file} must be a .docx, .pptx, or .xlsx file") + + # Work in temporary directory to avoid modifying original + with tempfile.TemporaryDirectory() as temp_dir: + temp_content_dir = Path(temp_dir) / "content" + shutil.copytree(input_dir, temp_content_dir) + + # Process XML files to remove pretty-printing whitespace + for pattern in ["*.xml", "*.rels"]: + for xml_file in temp_content_dir.rglob(pattern): + condense_xml(xml_file) + + # Create final Office file as zip archive + output_file.parent.mkdir(parents=True, exist_ok=True) + with zipfile.ZipFile(output_file, "w", zipfile.ZIP_DEFLATED) as zf: + for f in temp_content_dir.rglob("*"): + if f.is_file(): + zf.write(f, f.relative_to(temp_content_dir)) + + # Validate if requested + if validate: + if not validate_document(output_file): + output_file.unlink() # Delete the corrupt file + return False + + return True + + +def validate_document(doc_path): + """Validate document by converting to HTML with soffice.""" + # Determine the correct filter based on file extension + match doc_path.suffix.lower(): + case ".docx": + filter_name = "html:HTML" + case ".pptx": + filter_name = "html:impress_html_Export" + case ".xlsx": + filter_name = "html:HTML (StarCalc)" + + with tempfile.TemporaryDirectory() as temp_dir: + try: + result = subprocess.run( + [ + "soffice", + "--headless", + "--convert-to", + filter_name, + "--outdir", + temp_dir, + str(doc_path), + ], + capture_output=True, + timeout=10, + text=True, + ) + if not (Path(temp_dir) / f"{doc_path.stem}.html").exists(): + error_msg = result.stderr.strip() or "Document validation failed" + print(f"Validation error: {error_msg}", file=sys.stderr) + return False + return True + except FileNotFoundError: + print("Warning: soffice not found. Skipping validation.", file=sys.stderr) + return True + except subprocess.TimeoutExpired: + print("Validation error: Timeout during conversion", file=sys.stderr) + return False + except Exception as e: + print(f"Validation error: {e}", file=sys.stderr) + return False + + +def condense_xml(xml_file): + """Strip unnecessary whitespace and remove comments.""" + with open(xml_file, "r", encoding="utf-8") as f: + dom = defusedxml.minidom.parse(f) + + # Process each element to remove whitespace and comments + for element in dom.getElementsByTagName("*"): + # Skip w:t elements and their processing + if element.tagName.endswith(":t"): + continue + + # Remove whitespace-only text nodes and comment nodes + for child in list(element.childNodes): + if ( + child.nodeType == child.TEXT_NODE + and child.nodeValue + and child.nodeValue.strip() == "" + ) or child.nodeType == child.COMMENT_NODE: + element.removeChild(child) + + # Write back the condensed XML + with open(xml_file, "wb") as f: + f.write(dom.toxml(encoding="UTF-8")) + + +if __name__ == "__main__": + main() diff --git a/skills/docx/ooxml/scripts/unpack.py b/skills/docx/ooxml/scripts/unpack.py new file mode 100755 index 0000000..4938798 --- /dev/null +++ b/skills/docx/ooxml/scripts/unpack.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +"""Unpack and format XML contents of Office files (.docx, .pptx, .xlsx)""" + +import random +import sys +import defusedxml.minidom +import zipfile +from pathlib import Path + +# Get command line arguments +assert len(sys.argv) == 3, "Usage: python unpack.py " +input_file, output_dir = sys.argv[1], sys.argv[2] + +# Extract and format +output_path = Path(output_dir) +output_path.mkdir(parents=True, exist_ok=True) +zipfile.ZipFile(input_file).extractall(output_path) + +# Pretty print all XML files +xml_files = list(output_path.rglob("*.xml")) + list(output_path.rglob("*.rels")) +for xml_file in xml_files: + content = xml_file.read_text(encoding="utf-8") + dom = defusedxml.minidom.parseString(content) + xml_file.write_bytes(dom.toprettyxml(indent=" ", encoding="ascii")) + +# For .docx files, suggest an RSID for tracked changes +if input_file.endswith(".docx"): + suggested_rsid = "".join(random.choices("0123456789ABCDEF", k=8)) + print(f"Suggested RSID for edit session: {suggested_rsid}") diff --git a/skills/docx/ooxml/scripts/validate.py b/skills/docx/ooxml/scripts/validate.py new file mode 100755 index 0000000..508c589 --- /dev/null +++ b/skills/docx/ooxml/scripts/validate.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +""" +Command line tool to validate Office document XML files against XSD schemas and tracked changes. + +Usage: + python validate.py --original +""" + +import argparse +import sys +from pathlib import Path + +from validation import DOCXSchemaValidator, PPTXSchemaValidator, RedliningValidator + + +def main(): + parser = argparse.ArgumentParser(description="Validate Office document XML files") + parser.add_argument( + "unpacked_dir", + help="Path to unpacked Office document directory", + ) + parser.add_argument( + "--original", + required=True, + help="Path to original file (.docx/.pptx/.xlsx)", + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="Enable verbose output", + ) + args = parser.parse_args() + + # Validate paths + unpacked_dir = Path(args.unpacked_dir) + original_file = Path(args.original) + file_extension = original_file.suffix.lower() + assert unpacked_dir.is_dir(), f"Error: {unpacked_dir} is not a directory" + assert original_file.is_file(), f"Error: {original_file} is not a file" + assert file_extension in [".docx", ".pptx", ".xlsx"], ( + f"Error: {original_file} must be a .docx, .pptx, or .xlsx file" + ) + + # Run validations + match file_extension: + case ".docx": + validators = [DOCXSchemaValidator, RedliningValidator] + case ".pptx": + validators = [PPTXSchemaValidator] + case _: + print(f"Error: Validation not supported for file type {file_extension}") + sys.exit(1) + + # Run validators + success = True + for V in validators: + validator = V(unpacked_dir, original_file, verbose=args.verbose) + if not validator.validate(): + success = False + + if success: + print("All validations PASSED!") + + sys.exit(0 if success else 1) + + +if __name__ == "__main__": + main() diff --git a/skills/docx/ooxml/scripts/validation/__init__.py b/skills/docx/ooxml/scripts/validation/__init__.py new file mode 100755 index 0000000..db092ec --- /dev/null +++ b/skills/docx/ooxml/scripts/validation/__init__.py @@ -0,0 +1,15 @@ +""" +Validation modules for Word document processing. +""" + +from .base import BaseSchemaValidator +from .docx import DOCXSchemaValidator +from .pptx import PPTXSchemaValidator +from .redlining import RedliningValidator + +__all__ = [ + "BaseSchemaValidator", + "DOCXSchemaValidator", + "PPTXSchemaValidator", + "RedliningValidator", +] diff --git a/skills/docx/ooxml/scripts/validation/base.py b/skills/docx/ooxml/scripts/validation/base.py new file mode 100755 index 0000000..0681b19 --- /dev/null +++ b/skills/docx/ooxml/scripts/validation/base.py @@ -0,0 +1,951 @@ +""" +Base validator with common validation logic for document files. +""" + +import re +from pathlib import Path + +import lxml.etree + + +class BaseSchemaValidator: + """Base validator with common validation logic for document files.""" + + # Elements whose 'id' attributes must be unique within their file + # Format: element_name -> (attribute_name, scope) + # scope can be 'file' (unique within file) or 'global' (unique across all files) + UNIQUE_ID_REQUIREMENTS = { + # Word elements + "comment": ("id", "file"), # Comment IDs in comments.xml + "commentrangestart": ("id", "file"), # Must match comment IDs + "commentrangeend": ("id", "file"), # Must match comment IDs + "bookmarkstart": ("id", "file"), # Bookmark start IDs + "bookmarkend": ("id", "file"), # Bookmark end IDs + # Note: ins and del (track changes) can share IDs when part of same revision + # PowerPoint elements + "sldid": ("id", "file"), # Slide IDs in presentation.xml + "sldmasterid": ("id", "global"), # Slide master IDs must be globally unique + "sldlayoutid": ("id", "global"), # Slide layout IDs must be globally unique + "cm": ("authorid", "file"), # Comment author IDs + # Excel elements + "sheet": ("sheetid", "file"), # Sheet IDs in workbook.xml + "definedname": ("id", "file"), # Named range IDs + # Drawing/Shape elements (all formats) + "cxnsp": ("id", "file"), # Connection shape IDs + "sp": ("id", "file"), # Shape IDs + "pic": ("id", "file"), # Picture IDs + "grpsp": ("id", "file"), # Group shape IDs + } + + # Mapping of element names to expected relationship types + # Subclasses should override this with format-specific mappings + ELEMENT_RELATIONSHIP_TYPES = {} + + # Unified schema mappings for all Office document types + SCHEMA_MAPPINGS = { + # Document type specific schemas + "word": "ISO-IEC29500-4_2016/wml.xsd", # Word documents + "ppt": "ISO-IEC29500-4_2016/pml.xsd", # PowerPoint presentations + "xl": "ISO-IEC29500-4_2016/sml.xsd", # Excel spreadsheets + # Common file types + "[Content_Types].xml": "ecma/fouth-edition/opc-contentTypes.xsd", + "app.xml": "ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd", + "core.xml": "ecma/fouth-edition/opc-coreProperties.xsd", + "custom.xml": "ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd", + ".rels": "ecma/fouth-edition/opc-relationships.xsd", + # Word-specific files + "people.xml": "microsoft/wml-2012.xsd", + "commentsIds.xml": "microsoft/wml-cid-2016.xsd", + "commentsExtensible.xml": "microsoft/wml-cex-2018.xsd", + "commentsExtended.xml": "microsoft/wml-2012.xsd", + # Chart files (common across document types) + "chart": "ISO-IEC29500-4_2016/dml-chart.xsd", + # Theme files (common across document types) + "theme": "ISO-IEC29500-4_2016/dml-main.xsd", + # Drawing and media files + "drawing": "ISO-IEC29500-4_2016/dml-main.xsd", + } + + # Unified namespace constants + MC_NAMESPACE = "http://schemas.openxmlformats.org/markup-compatibility/2006" + XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace" + + # Common OOXML namespaces used across validators + PACKAGE_RELATIONSHIPS_NAMESPACE = ( + "http://schemas.openxmlformats.org/package/2006/relationships" + ) + OFFICE_RELATIONSHIPS_NAMESPACE = ( + "http://schemas.openxmlformats.org/officeDocument/2006/relationships" + ) + CONTENT_TYPES_NAMESPACE = ( + "http://schemas.openxmlformats.org/package/2006/content-types" + ) + + # Folders where we should clean ignorable namespaces + MAIN_CONTENT_FOLDERS = {"word", "ppt", "xl"} + + # All allowed OOXML namespaces (superset of all document types) + OOXML_NAMESPACES = { + "http://schemas.openxmlformats.org/officeDocument/2006/math", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + "http://schemas.openxmlformats.org/schemaLibrary/2006/main", + "http://schemas.openxmlformats.org/drawingml/2006/main", + "http://schemas.openxmlformats.org/drawingml/2006/chart", + "http://schemas.openxmlformats.org/drawingml/2006/chartDrawing", + "http://schemas.openxmlformats.org/drawingml/2006/diagram", + "http://schemas.openxmlformats.org/drawingml/2006/picture", + "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing", + "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", + "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + "http://schemas.openxmlformats.org/presentationml/2006/main", + "http://schemas.openxmlformats.org/spreadsheetml/2006/main", + "http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes", + "http://www.w3.org/XML/1998/namespace", + } + + def __init__(self, unpacked_dir, original_file, verbose=False): + self.unpacked_dir = Path(unpacked_dir).resolve() + self.original_file = Path(original_file) + self.verbose = verbose + + # Set schemas directory + self.schemas_dir = Path(__file__).parent.parent.parent / "schemas" + + # Get all XML and .rels files + patterns = ["*.xml", "*.rels"] + self.xml_files = [ + f for pattern in patterns for f in self.unpacked_dir.rglob(pattern) + ] + + if not self.xml_files: + print(f"Warning: No XML files found in {self.unpacked_dir}") + + def validate(self): + """Run all validation checks and return True if all pass.""" + raise NotImplementedError("Subclasses must implement the validate method") + + def validate_xml(self): + """Validate that all XML files are well-formed.""" + errors = [] + + for xml_file in self.xml_files: + try: + # Try to parse the XML file + lxml.etree.parse(str(xml_file)) + except lxml.etree.XMLSyntaxError as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {e.lineno}: {e.msg}" + ) + except Exception as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Unexpected error: {str(e)}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} XML violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All XML files are well-formed") + return True + + def validate_namespaces(self): + """Validate that namespace prefixes in Ignorable attributes are declared.""" + errors = [] + + for xml_file in self.xml_files: + try: + root = lxml.etree.parse(str(xml_file)).getroot() + declared = set(root.nsmap.keys()) - {None} # Exclude default namespace + + for attr_val in [ + v for k, v in root.attrib.items() if k.endswith("Ignorable") + ]: + undeclared = set(attr_val.split()) - declared + errors.extend( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Namespace '{ns}' in Ignorable but not declared" + for ns in undeclared + ) + except lxml.etree.XMLSyntaxError: + continue + + if errors: + print(f"FAILED - {len(errors)} namespace issues:") + for error in errors: + print(error) + return False + if self.verbose: + print("PASSED - All namespace prefixes properly declared") + return True + + def validate_unique_ids(self): + """Validate that specific IDs are unique according to OOXML requirements.""" + errors = [] + global_ids = {} # Track globally unique IDs across all files + + for xml_file in self.xml_files: + try: + root = lxml.etree.parse(str(xml_file)).getroot() + file_ids = {} # Track IDs that must be unique within this file + + # Remove all mc:AlternateContent elements from the tree + mc_elements = root.xpath( + ".//mc:AlternateContent", namespaces={"mc": self.MC_NAMESPACE} + ) + for elem in mc_elements: + elem.getparent().remove(elem) + + # Now check IDs in the cleaned tree + for elem in root.iter(): + # Get the element name without namespace + tag = ( + elem.tag.split("}")[-1].lower() + if "}" in elem.tag + else elem.tag.lower() + ) + + # Check if this element type has ID uniqueness requirements + if tag in self.UNIQUE_ID_REQUIREMENTS: + attr_name, scope = self.UNIQUE_ID_REQUIREMENTS[tag] + + # Look for the specified attribute + id_value = None + for attr, value in elem.attrib.items(): + attr_local = ( + attr.split("}")[-1].lower() + if "}" in attr + else attr.lower() + ) + if attr_local == attr_name: + id_value = value + break + + if id_value is not None: + if scope == "global": + # Check global uniqueness + if id_value in global_ids: + prev_file, prev_line, prev_tag = global_ids[ + id_value + ] + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: Global ID '{id_value}' in <{tag}> " + f"already used in {prev_file} at line {prev_line} in <{prev_tag}>" + ) + else: + global_ids[id_value] = ( + xml_file.relative_to(self.unpacked_dir), + elem.sourceline, + tag, + ) + elif scope == "file": + # Check file-level uniqueness + key = (tag, attr_name) + if key not in file_ids: + file_ids[key] = {} + + if id_value in file_ids[key]: + prev_line = file_ids[key][id_value] + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: Duplicate {attr_name}='{id_value}' in <{tag}> " + f"(first occurrence at line {prev_line})" + ) + else: + file_ids[key][id_value] = elem.sourceline + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} ID uniqueness violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All required IDs are unique") + return True + + def validate_file_references(self): + """ + Validate that all .rels files properly reference files and that all files are referenced. + """ + errors = [] + + # Find all .rels files + rels_files = list(self.unpacked_dir.rglob("*.rels")) + + if not rels_files: + if self.verbose: + print("PASSED - No .rels files found") + return True + + # Get all files in the unpacked directory (excluding reference files) + all_files = [] + for file_path in self.unpacked_dir.rglob("*"): + if ( + file_path.is_file() + and file_path.name != "[Content_Types].xml" + and not file_path.name.endswith(".rels") + ): # This file is not referenced by .rels + all_files.append(file_path.resolve()) + + # Track all files that are referenced by any .rels file + all_referenced_files = set() + + if self.verbose: + print( + f"Found {len(rels_files)} .rels files and {len(all_files)} target files" + ) + + # Check each .rels file + for rels_file in rels_files: + try: + # Parse relationships file + rels_root = lxml.etree.parse(str(rels_file)).getroot() + + # Get the directory where this .rels file is located + rels_dir = rels_file.parent + + # Find all relationships and their targets + referenced_files = set() + broken_refs = [] + + for rel in rels_root.findall( + ".//ns:Relationship", + namespaces={"ns": self.PACKAGE_RELATIONSHIPS_NAMESPACE}, + ): + target = rel.get("Target") + if target and not target.startswith( + ("http", "mailto:") + ): # Skip external URLs + # Resolve the target path relative to the .rels file location + if rels_file.name == ".rels": + # Root .rels file - targets are relative to unpacked_dir + target_path = self.unpacked_dir / target + else: + # Other .rels files - targets are relative to their parent's parent + # e.g., word/_rels/document.xml.rels -> targets relative to word/ + base_dir = rels_dir.parent + target_path = base_dir / target + + # Normalize the path and check if it exists + try: + target_path = target_path.resolve() + if target_path.exists() and target_path.is_file(): + referenced_files.add(target_path) + all_referenced_files.add(target_path) + else: + broken_refs.append((target, rel.sourceline)) + except (OSError, ValueError): + broken_refs.append((target, rel.sourceline)) + + # Report broken references + if broken_refs: + rel_path = rels_file.relative_to(self.unpacked_dir) + for broken_ref, line_num in broken_refs: + errors.append( + f" {rel_path}: Line {line_num}: Broken reference to {broken_ref}" + ) + + except Exception as e: + rel_path = rels_file.relative_to(self.unpacked_dir) + errors.append(f" Error parsing {rel_path}: {e}") + + # Check for unreferenced files (files that exist but are not referenced anywhere) + unreferenced_files = set(all_files) - all_referenced_files + + if unreferenced_files: + for unref_file in sorted(unreferenced_files): + unref_rel_path = unref_file.relative_to(self.unpacked_dir) + errors.append(f" Unreferenced file: {unref_rel_path}") + + if errors: + print(f"FAILED - Found {len(errors)} relationship validation errors:") + for error in errors: + print(error) + print( + "CRITICAL: These errors will cause the document to appear corrupt. " + + "Broken references MUST be fixed, " + + "and unreferenced files MUST be referenced or removed." + ) + return False + else: + if self.verbose: + print( + "PASSED - All references are valid and all files are properly referenced" + ) + return True + + def validate_all_relationship_ids(self): + """ + Validate that all r:id attributes in XML files reference existing IDs + in their corresponding .rels files, and optionally validate relationship types. + """ + import lxml.etree + + errors = [] + + # Process each XML file that might contain r:id references + for xml_file in self.xml_files: + # Skip .rels files themselves + if xml_file.suffix == ".rels": + continue + + # Determine the corresponding .rels file + # For dir/file.xml, it's dir/_rels/file.xml.rels + rels_dir = xml_file.parent / "_rels" + rels_file = rels_dir / f"{xml_file.name}.rels" + + # Skip if there's no corresponding .rels file (that's okay) + if not rels_file.exists(): + continue + + try: + # Parse the .rels file to get valid relationship IDs and their types + rels_root = lxml.etree.parse(str(rels_file)).getroot() + rid_to_type = {} + + for rel in rels_root.findall( + f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship" + ): + rid = rel.get("Id") + rel_type = rel.get("Type", "") + if rid: + # Check for duplicate rIds + if rid in rid_to_type: + rels_rel_path = rels_file.relative_to(self.unpacked_dir) + errors.append( + f" {rels_rel_path}: Line {rel.sourceline}: " + f"Duplicate relationship ID '{rid}' (IDs must be unique)" + ) + # Extract just the type name from the full URL + type_name = ( + rel_type.split("/")[-1] if "/" in rel_type else rel_type + ) + rid_to_type[rid] = type_name + + # Parse the XML file to find all r:id references + xml_root = lxml.etree.parse(str(xml_file)).getroot() + + # Find all elements with r:id attributes + for elem in xml_root.iter(): + # Check for r:id attribute (relationship ID) + rid_attr = elem.get(f"{{{self.OFFICE_RELATIONSHIPS_NAMESPACE}}}id") + if rid_attr: + xml_rel_path = xml_file.relative_to(self.unpacked_dir) + elem_name = ( + elem.tag.split("}")[-1] if "}" in elem.tag else elem.tag + ) + + # Check if the ID exists + if rid_attr not in rid_to_type: + errors.append( + f" {xml_rel_path}: Line {elem.sourceline}: " + f"<{elem_name}> references non-existent relationship '{rid_attr}' " + f"(valid IDs: {', '.join(sorted(rid_to_type.keys())[:5])}{'...' if len(rid_to_type) > 5 else ''})" + ) + # Check if we have type expectations for this element + elif self.ELEMENT_RELATIONSHIP_TYPES: + expected_type = self._get_expected_relationship_type( + elem_name + ) + if expected_type: + actual_type = rid_to_type[rid_attr] + # Check if the actual type matches or contains the expected type + if expected_type not in actual_type.lower(): + errors.append( + f" {xml_rel_path}: Line {elem.sourceline}: " + f"<{elem_name}> references '{rid_attr}' which points to '{actual_type}' " + f"but should point to a '{expected_type}' relationship" + ) + + except Exception as e: + xml_rel_path = xml_file.relative_to(self.unpacked_dir) + errors.append(f" Error processing {xml_rel_path}: {e}") + + if errors: + print(f"FAILED - Found {len(errors)} relationship ID reference errors:") + for error in errors: + print(error) + print("\nThese ID mismatches will cause the document to appear corrupt!") + return False + else: + if self.verbose: + print("PASSED - All relationship ID references are valid") + return True + + def _get_expected_relationship_type(self, element_name): + """ + Get the expected relationship type for an element. + First checks the explicit mapping, then tries pattern detection. + """ + # Normalize element name to lowercase + elem_lower = element_name.lower() + + # Check explicit mapping first + if elem_lower in self.ELEMENT_RELATIONSHIP_TYPES: + return self.ELEMENT_RELATIONSHIP_TYPES[elem_lower] + + # Try pattern detection for common patterns + # Pattern 1: Elements ending in "Id" often expect a relationship of the prefix type + if elem_lower.endswith("id") and len(elem_lower) > 2: + # e.g., "sldId" -> "sld", "sldMasterId" -> "sldMaster" + prefix = elem_lower[:-2] # Remove "id" + # Check if this might be a compound like "sldMasterId" + if prefix.endswith("master"): + return prefix.lower() + elif prefix.endswith("layout"): + return prefix.lower() + else: + # Simple case like "sldId" -> "slide" + # Common transformations + if prefix == "sld": + return "slide" + return prefix.lower() + + # Pattern 2: Elements ending in "Reference" expect a relationship of the prefix type + if elem_lower.endswith("reference") and len(elem_lower) > 9: + prefix = elem_lower[:-9] # Remove "reference" + return prefix.lower() + + return None + + def validate_content_types(self): + """Validate that all content files are properly declared in [Content_Types].xml.""" + errors = [] + + # Find [Content_Types].xml file + content_types_file = self.unpacked_dir / "[Content_Types].xml" + if not content_types_file.exists(): + print("FAILED - [Content_Types].xml file not found") + return False + + try: + # Parse and get all declared parts and extensions + root = lxml.etree.parse(str(content_types_file)).getroot() + declared_parts = set() + declared_extensions = set() + + # Get Override declarations (specific files) + for override in root.findall( + f".//{{{self.CONTENT_TYPES_NAMESPACE}}}Override" + ): + part_name = override.get("PartName") + if part_name is not None: + declared_parts.add(part_name.lstrip("/")) + + # Get Default declarations (by extension) + for default in root.findall( + f".//{{{self.CONTENT_TYPES_NAMESPACE}}}Default" + ): + extension = default.get("Extension") + if extension is not None: + declared_extensions.add(extension.lower()) + + # Root elements that require content type declaration + declarable_roots = { + "sld", + "sldLayout", + "sldMaster", + "presentation", # PowerPoint + "document", # Word + "workbook", + "worksheet", # Excel + "theme", # Common + } + + # Common media file extensions that should be declared + media_extensions = { + "png": "image/png", + "jpg": "image/jpeg", + "jpeg": "image/jpeg", + "gif": "image/gif", + "bmp": "image/bmp", + "tiff": "image/tiff", + "wmf": "image/x-wmf", + "emf": "image/x-emf", + } + + # Get all files in the unpacked directory + all_files = list(self.unpacked_dir.rglob("*")) + all_files = [f for f in all_files if f.is_file()] + + # Check all XML files for Override declarations + for xml_file in self.xml_files: + path_str = str(xml_file.relative_to(self.unpacked_dir)).replace( + "\\", "/" + ) + + # Skip non-content files + if any( + skip in path_str + for skip in [".rels", "[Content_Types]", "docProps/", "_rels/"] + ): + continue + + try: + root_tag = lxml.etree.parse(str(xml_file)).getroot().tag + root_name = root_tag.split("}")[-1] if "}" in root_tag else root_tag + + if root_name in declarable_roots and path_str not in declared_parts: + errors.append( + f" {path_str}: File with <{root_name}> root not declared in [Content_Types].xml" + ) + + except Exception: + continue # Skip unparseable files + + # Check all non-XML files for Default extension declarations + for file_path in all_files: + # Skip XML files and metadata files (already checked above) + if file_path.suffix.lower() in {".xml", ".rels"}: + continue + if file_path.name == "[Content_Types].xml": + continue + if "_rels" in file_path.parts or "docProps" in file_path.parts: + continue + + extension = file_path.suffix.lstrip(".").lower() + if extension and extension not in declared_extensions: + # Check if it's a known media extension that should be declared + if extension in media_extensions: + relative_path = file_path.relative_to(self.unpacked_dir) + errors.append( + f' {relative_path}: File with extension \'{extension}\' not declared in [Content_Types].xml - should add: ' + ) + + except Exception as e: + errors.append(f" Error parsing [Content_Types].xml: {e}") + + if errors: + print(f"FAILED - Found {len(errors)} content type declaration errors:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print( + "PASSED - All content files are properly declared in [Content_Types].xml" + ) + return True + + def validate_file_against_xsd(self, xml_file, verbose=False): + """Validate a single XML file against XSD schema, comparing with original. + + Args: + xml_file: Path to XML file to validate + verbose: Enable verbose output + + Returns: + tuple: (is_valid, new_errors_set) where is_valid is True/False/None (skipped) + """ + # Resolve both paths to handle symlinks + xml_file = Path(xml_file).resolve() + unpacked_dir = self.unpacked_dir.resolve() + + # Validate current file + is_valid, current_errors = self._validate_single_file_xsd( + xml_file, unpacked_dir + ) + + if is_valid is None: + return None, set() # Skipped + elif is_valid: + return True, set() # Valid, no errors + + # Get errors from original file for this specific file + original_errors = self._get_original_file_errors(xml_file) + + # Compare with original (both are guaranteed to be sets here) + assert current_errors is not None + new_errors = current_errors - original_errors + + if new_errors: + if verbose: + relative_path = xml_file.relative_to(unpacked_dir) + print(f"FAILED - {relative_path}: {len(new_errors)} new error(s)") + for error in list(new_errors)[:3]: + truncated = error[:250] + "..." if len(error) > 250 else error + print(f" - {truncated}") + return False, new_errors + else: + # All errors existed in original + if verbose: + print( + f"PASSED - No new errors (original had {len(current_errors)} errors)" + ) + return True, set() + + def validate_against_xsd(self): + """Validate XML files against XSD schemas, showing only new errors compared to original.""" + new_errors = [] + original_error_count = 0 + valid_count = 0 + skipped_count = 0 + + for xml_file in self.xml_files: + relative_path = str(xml_file.relative_to(self.unpacked_dir)) + is_valid, new_file_errors = self.validate_file_against_xsd( + xml_file, verbose=False + ) + + if is_valid is None: + skipped_count += 1 + continue + elif is_valid and not new_file_errors: + valid_count += 1 + continue + elif is_valid: + # Had errors but all existed in original + original_error_count += 1 + valid_count += 1 + continue + + # Has new errors + new_errors.append(f" {relative_path}: {len(new_file_errors)} new error(s)") + for error in list(new_file_errors)[:3]: # Show first 3 errors + new_errors.append( + f" - {error[:250]}..." if len(error) > 250 else f" - {error}" + ) + + # Print summary + if self.verbose: + print(f"Validated {len(self.xml_files)} files:") + print(f" - Valid: {valid_count}") + print(f" - Skipped (no schema): {skipped_count}") + if original_error_count: + print(f" - With original errors (ignored): {original_error_count}") + print( + f" - With NEW errors: {len(new_errors) > 0 and len([e for e in new_errors if not e.startswith(' ')]) or 0}" + ) + + if new_errors: + print("\nFAILED - Found NEW validation errors:") + for error in new_errors: + print(error) + return False + else: + if self.verbose: + print("\nPASSED - No new XSD validation errors introduced") + return True + + def _get_schema_path(self, xml_file): + """Determine the appropriate schema path for an XML file.""" + # Check exact filename match + if xml_file.name in self.SCHEMA_MAPPINGS: + return self.schemas_dir / self.SCHEMA_MAPPINGS[xml_file.name] + + # Check .rels files + if xml_file.suffix == ".rels": + return self.schemas_dir / self.SCHEMA_MAPPINGS[".rels"] + + # Check chart files + if "charts/" in str(xml_file) and xml_file.name.startswith("chart"): + return self.schemas_dir / self.SCHEMA_MAPPINGS["chart"] + + # Check theme files + if "theme/" in str(xml_file) and xml_file.name.startswith("theme"): + return self.schemas_dir / self.SCHEMA_MAPPINGS["theme"] + + # Check if file is in a main content folder and use appropriate schema + if xml_file.parent.name in self.MAIN_CONTENT_FOLDERS: + return self.schemas_dir / self.SCHEMA_MAPPINGS[xml_file.parent.name] + + return None + + def _clean_ignorable_namespaces(self, xml_doc): + """Remove attributes and elements not in allowed namespaces.""" + # Create a clean copy + xml_string = lxml.etree.tostring(xml_doc, encoding="unicode") + xml_copy = lxml.etree.fromstring(xml_string) + + # Remove attributes not in allowed namespaces + for elem in xml_copy.iter(): + attrs_to_remove = [] + + for attr in elem.attrib: + # Check if attribute is from a namespace other than allowed ones + if "{" in attr: + ns = attr.split("}")[0][1:] + if ns not in self.OOXML_NAMESPACES: + attrs_to_remove.append(attr) + + # Remove collected attributes + for attr in attrs_to_remove: + del elem.attrib[attr] + + # Remove elements not in allowed namespaces + self._remove_ignorable_elements(xml_copy) + + return lxml.etree.ElementTree(xml_copy) + + def _remove_ignorable_elements(self, root): + """Recursively remove all elements not in allowed namespaces.""" + elements_to_remove = [] + + # Find elements to remove + for elem in list(root): + # Skip non-element nodes (comments, processing instructions, etc.) + if not hasattr(elem, "tag") or callable(elem.tag): + continue + + tag_str = str(elem.tag) + if tag_str.startswith("{"): + ns = tag_str.split("}")[0][1:] + if ns not in self.OOXML_NAMESPACES: + elements_to_remove.append(elem) + continue + + # Recursively clean child elements + self._remove_ignorable_elements(elem) + + # Remove collected elements + for elem in elements_to_remove: + root.remove(elem) + + def _preprocess_for_mc_ignorable(self, xml_doc): + """Preprocess XML to handle mc:Ignorable attribute properly.""" + # Remove mc:Ignorable attributes before validation + root = xml_doc.getroot() + + # Remove mc:Ignorable attribute from root + if f"{{{self.MC_NAMESPACE}}}Ignorable" in root.attrib: + del root.attrib[f"{{{self.MC_NAMESPACE}}}Ignorable"] + + return xml_doc + + def _validate_single_file_xsd(self, xml_file, base_path): + """Validate a single XML file against XSD schema. Returns (is_valid, errors_set).""" + schema_path = self._get_schema_path(xml_file) + if not schema_path: + return None, None # Skip file + + try: + # Load schema + with open(schema_path, "rb") as xsd_file: + parser = lxml.etree.XMLParser() + xsd_doc = lxml.etree.parse( + xsd_file, parser=parser, base_url=str(schema_path) + ) + schema = lxml.etree.XMLSchema(xsd_doc) + + # Load and preprocess XML + with open(xml_file, "r") as f: + xml_doc = lxml.etree.parse(f) + + xml_doc, _ = self._remove_template_tags_from_text_nodes(xml_doc) + xml_doc = self._preprocess_for_mc_ignorable(xml_doc) + + # Clean ignorable namespaces if needed + relative_path = xml_file.relative_to(base_path) + if ( + relative_path.parts + and relative_path.parts[0] in self.MAIN_CONTENT_FOLDERS + ): + xml_doc = self._clean_ignorable_namespaces(xml_doc) + + # Validate + if schema.validate(xml_doc): + return True, set() + else: + errors = set() + for error in schema.error_log: + # Store normalized error message (without line numbers for comparison) + errors.add(error.message) + return False, errors + + except Exception as e: + return False, {str(e)} + + def _get_original_file_errors(self, xml_file): + """Get XSD validation errors from a single file in the original document. + + Args: + xml_file: Path to the XML file in unpacked_dir to check + + Returns: + set: Set of error messages from the original file + """ + import tempfile + import zipfile + + # Resolve both paths to handle symlinks (e.g., /var vs /private/var on macOS) + xml_file = Path(xml_file).resolve() + unpacked_dir = self.unpacked_dir.resolve() + relative_path = xml_file.relative_to(unpacked_dir) + + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + + # Extract original file + with zipfile.ZipFile(self.original_file, "r") as zip_ref: + zip_ref.extractall(temp_path) + + # Find corresponding file in original + original_xml_file = temp_path / relative_path + + if not original_xml_file.exists(): + # File didn't exist in original, so no original errors + return set() + + # Validate the specific file in original + is_valid, errors = self._validate_single_file_xsd( + original_xml_file, temp_path + ) + return errors if errors else set() + + def _remove_template_tags_from_text_nodes(self, xml_doc): + """Remove template tags from XML text nodes and collect warnings. + + Template tags follow the pattern {{ ... }} and are used as placeholders + for content replacement. They should be removed from text content before + XSD validation while preserving XML structure. + + Returns: + tuple: (cleaned_xml_doc, warnings_list) + """ + warnings = [] + template_pattern = re.compile(r"\{\{[^}]*\}\}") + + # Create a copy of the document to avoid modifying the original + xml_string = lxml.etree.tostring(xml_doc, encoding="unicode") + xml_copy = lxml.etree.fromstring(xml_string) + + def process_text_content(text, content_type): + if not text: + return text + matches = list(template_pattern.finditer(text)) + if matches: + for match in matches: + warnings.append( + f"Found template tag in {content_type}: {match.group()}" + ) + return template_pattern.sub("", text) + return text + + # Process all text nodes in the document + for elem in xml_copy.iter(): + # Skip processing if this is a w:t element + if not hasattr(elem, "tag") or callable(elem.tag): + continue + tag_str = str(elem.tag) + if tag_str.endswith("}t") or tag_str == "t": + continue + + elem.text = process_text_content(elem.text, "text content") + elem.tail = process_text_content(elem.tail, "tail content") + + return lxml.etree.ElementTree(xml_copy), warnings + + +if __name__ == "__main__": + raise RuntimeError("This module should not be run directly.") diff --git a/skills/docx/ooxml/scripts/validation/docx.py b/skills/docx/ooxml/scripts/validation/docx.py new file mode 100755 index 0000000..602c470 --- /dev/null +++ b/skills/docx/ooxml/scripts/validation/docx.py @@ -0,0 +1,274 @@ +""" +Validator for Word document XML files against XSD schemas. +""" + +import re +import tempfile +import zipfile + +import lxml.etree + +from .base import BaseSchemaValidator + + +class DOCXSchemaValidator(BaseSchemaValidator): + """Validator for Word document XML files against XSD schemas.""" + + # Word-specific namespace + WORD_2006_NAMESPACE = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" + + # Word-specific element to relationship type mappings + # Start with empty mapping - add specific cases as we discover them + ELEMENT_RELATIONSHIP_TYPES = {} + + def validate(self): + """Run all validation checks and return True if all pass.""" + # Test 0: XML well-formedness + if not self.validate_xml(): + return False + + # Test 1: Namespace declarations + all_valid = True + if not self.validate_namespaces(): + all_valid = False + + # Test 2: Unique IDs + if not self.validate_unique_ids(): + all_valid = False + + # Test 3: Relationship and file reference validation + if not self.validate_file_references(): + all_valid = False + + # Test 4: Content type declarations + if not self.validate_content_types(): + all_valid = False + + # Test 5: XSD schema validation + if not self.validate_against_xsd(): + all_valid = False + + # Test 6: Whitespace preservation + if not self.validate_whitespace_preservation(): + all_valid = False + + # Test 7: Deletion validation + if not self.validate_deletions(): + all_valid = False + + # Test 8: Insertion validation + if not self.validate_insertions(): + all_valid = False + + # Test 9: Relationship ID reference validation + if not self.validate_all_relationship_ids(): + all_valid = False + + # Count and compare paragraphs + self.compare_paragraph_counts() + + return all_valid + + def validate_whitespace_preservation(self): + """ + Validate that w:t elements with whitespace have xml:space='preserve'. + """ + errors = [] + + for xml_file in self.xml_files: + # Only check document.xml files + if xml_file.name != "document.xml": + continue + + try: + root = lxml.etree.parse(str(xml_file)).getroot() + + # Find all w:t elements + for elem in root.iter(f"{{{self.WORD_2006_NAMESPACE}}}t"): + if elem.text: + text = elem.text + # Check if text starts or ends with whitespace + if re.match(r"^\s.*", text) or re.match(r".*\s$", text): + # Check if xml:space="preserve" attribute exists + xml_space_attr = f"{{{self.XML_NAMESPACE}}}space" + if ( + xml_space_attr not in elem.attrib + or elem.attrib[xml_space_attr] != "preserve" + ): + # Show a preview of the text + text_preview = ( + repr(text)[:50] + "..." + if len(repr(text)) > 50 + else repr(text) + ) + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: w:t element with whitespace missing xml:space='preserve': {text_preview}" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} whitespace preservation violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All whitespace is properly preserved") + return True + + def validate_deletions(self): + """ + Validate that w:t elements are not within w:del elements. + For some reason, XSD validation does not catch this, so we do it manually. + """ + errors = [] + + for xml_file in self.xml_files: + # Only check document.xml files + if xml_file.name != "document.xml": + continue + + try: + root = lxml.etree.parse(str(xml_file)).getroot() + + # Find all w:t elements that are descendants of w:del elements + namespaces = {"w": self.WORD_2006_NAMESPACE} + xpath_expression = ".//w:del//w:t" + problematic_t_elements = root.xpath( + xpath_expression, namespaces=namespaces + ) + for t_elem in problematic_t_elements: + if t_elem.text: + # Show a preview of the text + text_preview = ( + repr(t_elem.text)[:50] + "..." + if len(repr(t_elem.text)) > 50 + else repr(t_elem.text) + ) + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {t_elem.sourceline}: found within : {text_preview}" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} deletion validation violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - No w:t elements found within w:del elements") + return True + + def count_paragraphs_in_unpacked(self): + """Count the number of paragraphs in the unpacked document.""" + count = 0 + + for xml_file in self.xml_files: + # Only check document.xml files + if xml_file.name != "document.xml": + continue + + try: + root = lxml.etree.parse(str(xml_file)).getroot() + # Count all w:p elements + paragraphs = root.findall(f".//{{{self.WORD_2006_NAMESPACE}}}p") + count = len(paragraphs) + except Exception as e: + print(f"Error counting paragraphs in unpacked document: {e}") + + return count + + def count_paragraphs_in_original(self): + """Count the number of paragraphs in the original docx file.""" + count = 0 + + try: + # Create temporary directory to unpack original + with tempfile.TemporaryDirectory() as temp_dir: + # Unpack original docx + with zipfile.ZipFile(self.original_file, "r") as zip_ref: + zip_ref.extractall(temp_dir) + + # Parse document.xml + doc_xml_path = temp_dir + "/word/document.xml" + root = lxml.etree.parse(doc_xml_path).getroot() + + # Count all w:p elements + paragraphs = root.findall(f".//{{{self.WORD_2006_NAMESPACE}}}p") + count = len(paragraphs) + + except Exception as e: + print(f"Error counting paragraphs in original document: {e}") + + return count + + def validate_insertions(self): + """ + Validate that w:delText elements are not within w:ins elements. + w:delText is only allowed in w:ins if nested within a w:del. + """ + errors = [] + + for xml_file in self.xml_files: + if xml_file.name != "document.xml": + continue + + try: + root = lxml.etree.parse(str(xml_file)).getroot() + namespaces = {"w": self.WORD_2006_NAMESPACE} + + # Find w:delText in w:ins that are NOT within w:del + invalid_elements = root.xpath( + ".//w:ins//w:delText[not(ancestor::w:del)]", + namespaces=namespaces + ) + + for elem in invalid_elements: + text_preview = ( + repr(elem.text or "")[:50] + "..." + if len(repr(elem.text or "")) > 50 + else repr(elem.text or "") + ) + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: within : {text_preview}" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} insertion validation violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - No w:delText elements within w:ins elements") + return True + + def compare_paragraph_counts(self): + """Compare paragraph counts between original and new document.""" + original_count = self.count_paragraphs_in_original() + new_count = self.count_paragraphs_in_unpacked() + + diff = new_count - original_count + diff_str = f"+{diff}" if diff > 0 else str(diff) + print(f"\nParagraphs: {original_count} → {new_count} ({diff_str})") + + +if __name__ == "__main__": + raise RuntimeError("This module should not be run directly.") diff --git a/skills/docx/ooxml/scripts/validation/pptx.py b/skills/docx/ooxml/scripts/validation/pptx.py new file mode 100755 index 0000000..66d5b1e --- /dev/null +++ b/skills/docx/ooxml/scripts/validation/pptx.py @@ -0,0 +1,315 @@ +""" +Validator for PowerPoint presentation XML files against XSD schemas. +""" + +import re + +from .base import BaseSchemaValidator + + +class PPTXSchemaValidator(BaseSchemaValidator): + """Validator for PowerPoint presentation XML files against XSD schemas.""" + + # PowerPoint presentation namespace + PRESENTATIONML_NAMESPACE = ( + "http://schemas.openxmlformats.org/presentationml/2006/main" + ) + + # PowerPoint-specific element to relationship type mappings + ELEMENT_RELATIONSHIP_TYPES = { + "sldid": "slide", + "sldmasterid": "slidemaster", + "notesmasterid": "notesmaster", + "sldlayoutid": "slidelayout", + "themeid": "theme", + "tablestyleid": "tablestyles", + } + + def validate(self): + """Run all validation checks and return True if all pass.""" + # Test 0: XML well-formedness + if not self.validate_xml(): + return False + + # Test 1: Namespace declarations + all_valid = True + if not self.validate_namespaces(): + all_valid = False + + # Test 2: Unique IDs + if not self.validate_unique_ids(): + all_valid = False + + # Test 3: UUID ID validation + if not self.validate_uuid_ids(): + all_valid = False + + # Test 4: Relationship and file reference validation + if not self.validate_file_references(): + all_valid = False + + # Test 5: Slide layout ID validation + if not self.validate_slide_layout_ids(): + all_valid = False + + # Test 6: Content type declarations + if not self.validate_content_types(): + all_valid = False + + # Test 7: XSD schema validation + if not self.validate_against_xsd(): + all_valid = False + + # Test 8: Notes slide reference validation + if not self.validate_notes_slide_references(): + all_valid = False + + # Test 9: Relationship ID reference validation + if not self.validate_all_relationship_ids(): + all_valid = False + + # Test 10: Duplicate slide layout references validation + if not self.validate_no_duplicate_slide_layouts(): + all_valid = False + + return all_valid + + def validate_uuid_ids(self): + """Validate that ID attributes that look like UUIDs contain only hex values.""" + import lxml.etree + + errors = [] + # UUID pattern: 8-4-4-4-12 hex digits with optional braces/hyphens + uuid_pattern = re.compile( + r"^[\{\(]?[0-9A-Fa-f]{8}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{12}[\}\)]?$" + ) + + for xml_file in self.xml_files: + try: + root = lxml.etree.parse(str(xml_file)).getroot() + + # Check all elements for ID attributes + for elem in root.iter(): + for attr, value in elem.attrib.items(): + # Check if this is an ID attribute + attr_name = attr.split("}")[-1].lower() + if attr_name == "id" or attr_name.endswith("id"): + # Check if value looks like a UUID (has the right length and pattern structure) + if self._looks_like_uuid(value): + # Validate that it contains only hex characters in the right positions + if not uuid_pattern.match(value): + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: ID '{value}' appears to be a UUID but contains invalid hex characters" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} UUID ID validation errors:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All UUID-like IDs contain valid hex values") + return True + + def _looks_like_uuid(self, value): + """Check if a value has the general structure of a UUID.""" + # Remove common UUID delimiters + clean_value = value.strip("{}()").replace("-", "") + # Check if it's 32 hex-like characters (could include invalid hex chars) + return len(clean_value) == 32 and all(c.isalnum() for c in clean_value) + + def validate_slide_layout_ids(self): + """Validate that sldLayoutId elements in slide masters reference valid slide layouts.""" + import lxml.etree + + errors = [] + + # Find all slide master files + slide_masters = list(self.unpacked_dir.glob("ppt/slideMasters/*.xml")) + + if not slide_masters: + if self.verbose: + print("PASSED - No slide masters found") + return True + + for slide_master in slide_masters: + try: + # Parse the slide master file + root = lxml.etree.parse(str(slide_master)).getroot() + + # Find the corresponding _rels file for this slide master + rels_file = slide_master.parent / "_rels" / f"{slide_master.name}.rels" + + if not rels_file.exists(): + errors.append( + f" {slide_master.relative_to(self.unpacked_dir)}: " + f"Missing relationships file: {rels_file.relative_to(self.unpacked_dir)}" + ) + continue + + # Parse the relationships file + rels_root = lxml.etree.parse(str(rels_file)).getroot() + + # Build a set of valid relationship IDs that point to slide layouts + valid_layout_rids = set() + for rel in rels_root.findall( + f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship" + ): + rel_type = rel.get("Type", "") + if "slideLayout" in rel_type: + valid_layout_rids.add(rel.get("Id")) + + # Find all sldLayoutId elements in the slide master + for sld_layout_id in root.findall( + f".//{{{self.PRESENTATIONML_NAMESPACE}}}sldLayoutId" + ): + r_id = sld_layout_id.get( + f"{{{self.OFFICE_RELATIONSHIPS_NAMESPACE}}}id" + ) + layout_id = sld_layout_id.get("id") + + if r_id and r_id not in valid_layout_rids: + errors.append( + f" {slide_master.relative_to(self.unpacked_dir)}: " + f"Line {sld_layout_id.sourceline}: sldLayoutId with id='{layout_id}' " + f"references r:id='{r_id}' which is not found in slide layout relationships" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {slide_master.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} slide layout ID validation errors:") + for error in errors: + print(error) + print( + "Remove invalid references or add missing slide layouts to the relationships file." + ) + return False + else: + if self.verbose: + print("PASSED - All slide layout IDs reference valid slide layouts") + return True + + def validate_no_duplicate_slide_layouts(self): + """Validate that each slide has exactly one slideLayout reference.""" + import lxml.etree + + errors = [] + slide_rels_files = list(self.unpacked_dir.glob("ppt/slides/_rels/*.xml.rels")) + + for rels_file in slide_rels_files: + try: + root = lxml.etree.parse(str(rels_file)).getroot() + + # Find all slideLayout relationships + layout_rels = [ + rel + for rel in root.findall( + f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship" + ) + if "slideLayout" in rel.get("Type", "") + ] + + if len(layout_rels) > 1: + errors.append( + f" {rels_file.relative_to(self.unpacked_dir)}: has {len(layout_rels)} slideLayout references" + ) + + except Exception as e: + errors.append( + f" {rels_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print("FAILED - Found slides with duplicate slideLayout references:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All slides have exactly one slideLayout reference") + return True + + def validate_notes_slide_references(self): + """Validate that each notesSlide file is referenced by only one slide.""" + import lxml.etree + + errors = [] + notes_slide_references = {} # Track which slides reference each notesSlide + + # Find all slide relationship files + slide_rels_files = list(self.unpacked_dir.glob("ppt/slides/_rels/*.xml.rels")) + + if not slide_rels_files: + if self.verbose: + print("PASSED - No slide relationship files found") + return True + + for rels_file in slide_rels_files: + try: + # Parse the relationships file + root = lxml.etree.parse(str(rels_file)).getroot() + + # Find all notesSlide relationships + for rel in root.findall( + f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship" + ): + rel_type = rel.get("Type", "") + if "notesSlide" in rel_type: + target = rel.get("Target", "") + if target: + # Normalize the target path to handle relative paths + normalized_target = target.replace("../", "") + + # Track which slide references this notesSlide + slide_name = rels_file.stem.replace( + ".xml", "" + ) # e.g., "slide1" + + if normalized_target not in notes_slide_references: + notes_slide_references[normalized_target] = [] + notes_slide_references[normalized_target].append( + (slide_name, rels_file) + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {rels_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + # Check for duplicate references + for target, references in notes_slide_references.items(): + if len(references) > 1: + slide_names = [ref[0] for ref in references] + errors.append( + f" Notes slide '{target}' is referenced by multiple slides: {', '.join(slide_names)}" + ) + for slide_name, rels_file in references: + errors.append(f" - {rels_file.relative_to(self.unpacked_dir)}") + + if errors: + print( + f"FAILED - Found {len([e for e in errors if not e.startswith(' ')])} notes slide reference validation errors:" + ) + for error in errors: + print(error) + print("Each slide may optionally have its own slide file.") + return False + else: + if self.verbose: + print("PASSED - All notes slide references are unique") + return True + + +if __name__ == "__main__": + raise RuntimeError("This module should not be run directly.") diff --git a/skills/docx/ooxml/scripts/validation/redlining.py b/skills/docx/ooxml/scripts/validation/redlining.py new file mode 100755 index 0000000..7ed425e --- /dev/null +++ b/skills/docx/ooxml/scripts/validation/redlining.py @@ -0,0 +1,279 @@ +""" +Validator for tracked changes in Word documents. +""" + +import subprocess +import tempfile +import zipfile +from pathlib import Path + + +class RedliningValidator: + """Validator for tracked changes in Word documents.""" + + def __init__(self, unpacked_dir, original_docx, verbose=False): + self.unpacked_dir = Path(unpacked_dir) + self.original_docx = Path(original_docx) + self.verbose = verbose + self.namespaces = { + "w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main" + } + + def validate(self): + """Main validation method that returns True if valid, False otherwise.""" + # Verify unpacked directory exists and has correct structure + modified_file = self.unpacked_dir / "word" / "document.xml" + if not modified_file.exists(): + print(f"FAILED - Modified document.xml not found at {modified_file}") + return False + + # First, check if there are any tracked changes by Claude to validate + try: + import xml.etree.ElementTree as ET + + tree = ET.parse(modified_file) + root = tree.getroot() + + # Check for w:del or w:ins tags authored by Claude + del_elements = root.findall(".//w:del", self.namespaces) + ins_elements = root.findall(".//w:ins", self.namespaces) + + # Filter to only include changes by Claude + claude_del_elements = [ + elem + for elem in del_elements + if elem.get(f"{{{self.namespaces['w']}}}author") == "Claude" + ] + claude_ins_elements = [ + elem + for elem in ins_elements + if elem.get(f"{{{self.namespaces['w']}}}author") == "Claude" + ] + + # Redlining validation is only needed if tracked changes by Claude have been used. + if not claude_del_elements and not claude_ins_elements: + if self.verbose: + print("PASSED - No tracked changes by Claude found.") + return True + + except Exception: + # If we can't parse the XML, continue with full validation + pass + + # Create temporary directory for unpacking original docx + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + + # Unpack original docx + try: + with zipfile.ZipFile(self.original_docx, "r") as zip_ref: + zip_ref.extractall(temp_path) + except Exception as e: + print(f"FAILED - Error unpacking original docx: {e}") + return False + + original_file = temp_path / "word" / "document.xml" + if not original_file.exists(): + print( + f"FAILED - Original document.xml not found in {self.original_docx}" + ) + return False + + # Parse both XML files using xml.etree.ElementTree for redlining validation + try: + import xml.etree.ElementTree as ET + + modified_tree = ET.parse(modified_file) + modified_root = modified_tree.getroot() + original_tree = ET.parse(original_file) + original_root = original_tree.getroot() + except ET.ParseError as e: + print(f"FAILED - Error parsing XML files: {e}") + return False + + # Remove Claude's tracked changes from both documents + self._remove_claude_tracked_changes(original_root) + self._remove_claude_tracked_changes(modified_root) + + # Extract and compare text content + modified_text = self._extract_text_content(modified_root) + original_text = self._extract_text_content(original_root) + + if modified_text != original_text: + # Show detailed character-level differences for each paragraph + error_message = self._generate_detailed_diff( + original_text, modified_text + ) + print(error_message) + return False + + if self.verbose: + print("PASSED - All changes by Claude are properly tracked") + return True + + def _generate_detailed_diff(self, original_text, modified_text): + """Generate detailed word-level differences using git word diff.""" + error_parts = [ + "FAILED - Document text doesn't match after removing Claude's tracked changes", + "", + "Likely causes:", + " 1. Modified text inside another author's or tags", + " 2. Made edits without proper tracked changes", + " 3. Didn't nest inside when deleting another's insertion", + "", + "For pre-redlined documents, use correct patterns:", + " - To reject another's INSERTION: Nest inside their ", + " - To restore another's DELETION: Add new AFTER their ", + "", + ] + + # Show git word diff + git_diff = self._get_git_word_diff(original_text, modified_text) + if git_diff: + error_parts.extend(["Differences:", "============", git_diff]) + else: + error_parts.append("Unable to generate word diff (git not available)") + + return "\n".join(error_parts) + + def _get_git_word_diff(self, original_text, modified_text): + """Generate word diff using git with character-level precision.""" + try: + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + + # Create two files + original_file = temp_path / "original.txt" + modified_file = temp_path / "modified.txt" + + original_file.write_text(original_text, encoding="utf-8") + modified_file.write_text(modified_text, encoding="utf-8") + + # Try character-level diff first for precise differences + result = subprocess.run( + [ + "git", + "diff", + "--word-diff=plain", + "--word-diff-regex=.", # Character-by-character diff + "-U0", # Zero lines of context - show only changed lines + "--no-index", + str(original_file), + str(modified_file), + ], + capture_output=True, + text=True, + ) + + if result.stdout.strip(): + # Clean up the output - remove git diff header lines + lines = result.stdout.split("\n") + # Skip the header lines (diff --git, index, +++, ---, @@) + content_lines = [] + in_content = False + for line in lines: + if line.startswith("@@"): + in_content = True + continue + if in_content and line.strip(): + content_lines.append(line) + + if content_lines: + return "\n".join(content_lines) + + # Fallback to word-level diff if character-level is too verbose + result = subprocess.run( + [ + "git", + "diff", + "--word-diff=plain", + "-U0", # Zero lines of context + "--no-index", + str(original_file), + str(modified_file), + ], + capture_output=True, + text=True, + ) + + if result.stdout.strip(): + lines = result.stdout.split("\n") + content_lines = [] + in_content = False + for line in lines: + if line.startswith("@@"): + in_content = True + continue + if in_content and line.strip(): + content_lines.append(line) + return "\n".join(content_lines) + + except (subprocess.CalledProcessError, FileNotFoundError, Exception): + # Git not available or other error, return None to use fallback + pass + + return None + + def _remove_claude_tracked_changes(self, root): + """Remove tracked changes authored by Claude from the XML root.""" + ins_tag = f"{{{self.namespaces['w']}}}ins" + del_tag = f"{{{self.namespaces['w']}}}del" + author_attr = f"{{{self.namespaces['w']}}}author" + + # Remove w:ins elements + for parent in root.iter(): + to_remove = [] + for child in parent: + if child.tag == ins_tag and child.get(author_attr) == "Claude": + to_remove.append(child) + for elem in to_remove: + parent.remove(elem) + + # Unwrap content in w:del elements where author is "Claude" + deltext_tag = f"{{{self.namespaces['w']}}}delText" + t_tag = f"{{{self.namespaces['w']}}}t" + + for parent in root.iter(): + to_process = [] + for child in parent: + if child.tag == del_tag and child.get(author_attr) == "Claude": + to_process.append((child, list(parent).index(child))) + + # Process in reverse order to maintain indices + for del_elem, del_index in reversed(to_process): + # Convert w:delText to w:t before moving + for elem in del_elem.iter(): + if elem.tag == deltext_tag: + elem.tag = t_tag + + # Move all children of w:del to its parent before removing w:del + for child in reversed(list(del_elem)): + parent.insert(del_index, child) + parent.remove(del_elem) + + def _extract_text_content(self, root): + """Extract text content from Word XML, preserving paragraph structure. + + Empty paragraphs are skipped to avoid false positives when tracked + insertions add only structural elements without text content. + """ + p_tag = f"{{{self.namespaces['w']}}}p" + t_tag = f"{{{self.namespaces['w']}}}t" + + paragraphs = [] + for p_elem in root.findall(f".//{p_tag}"): + # Get all text elements within this paragraph + text_parts = [] + for t_elem in p_elem.findall(f".//{t_tag}"): + if t_elem.text: + text_parts.append(t_elem.text) + paragraph_text = "".join(text_parts) + # Skip empty paragraphs - they don't affect content validation + if paragraph_text: + paragraphs.append(paragraph_text) + + return "\n".join(paragraphs) + + +if __name__ == "__main__": + raise RuntimeError("This module should not be run directly.") diff --git a/skills/docx/scripts/__init__.py b/skills/docx/scripts/__init__.py new file mode 100755 index 0000000..bf9c562 --- /dev/null +++ b/skills/docx/scripts/__init__.py @@ -0,0 +1 @@ +# Make scripts directory a package for relative imports in tests diff --git a/skills/docx/scripts/document.py b/skills/docx/scripts/document.py new file mode 100755 index 0000000..ae9328d --- /dev/null +++ b/skills/docx/scripts/document.py @@ -0,0 +1,1276 @@ +#!/usr/bin/env python3 +""" +Library for working with Word documents: comments, tracked changes, and editing. + +Usage: + from skills.docx.scripts.document import Document + + # Initialize + doc = Document('workspace/unpacked') + doc = Document('workspace/unpacked', author="John Doe", initials="JD") + + # Find nodes + node = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "1"}) + node = doc["word/document.xml"].get_node(tag="w:p", line_number=10) + + # Add comments + doc.add_comment(start=node, end=node, text="Comment text") + doc.reply_to_comment(parent_comment_id=0, text="Reply text") + + # Suggest tracked changes + doc["word/document.xml"].suggest_deletion(node) # Delete content + doc["word/document.xml"].revert_insertion(ins_node) # Reject insertion + doc["word/document.xml"].revert_deletion(del_node) # Reject deletion + + # Save + doc.save() +""" + +import html +import random +import shutil +import tempfile +from datetime import datetime, timezone +from pathlib import Path + +from defusedxml import minidom +from ooxml.scripts.pack import pack_document +from ooxml.scripts.validation.docx import DOCXSchemaValidator +from ooxml.scripts.validation.redlining import RedliningValidator + +from .utilities import XMLEditor + +# Path to template files +TEMPLATE_DIR = Path(__file__).parent / "templates" + + +class DocxXMLEditor(XMLEditor): + """XMLEditor that automatically applies RSID, author, and date to new elements. + + Automatically adds attributes to elements that support them when inserting new content: + - w:rsidR, w:rsidRDefault, w:rsidP (for w:p and w:r elements) + - w:author and w:date (for w:ins, w:del, w:comment elements) + - w:id (for w:ins and w:del elements) + + Attributes: + dom (defusedxml.minidom.Document): The DOM document for direct manipulation + """ + + def __init__( + self, xml_path, rsid: str, author: str = "Claude", initials: str = "C" + ): + """Initialize with required RSID and optional author. + + Args: + xml_path: Path to XML file to edit + rsid: RSID to automatically apply to new elements + author: Author name for tracked changes and comments (default: "Claude") + initials: Author initials (default: "C") + """ + super().__init__(xml_path) + self.rsid = rsid + self.author = author + self.initials = initials + + def _get_next_change_id(self): + """Get the next available change ID by checking all tracked change elements.""" + max_id = -1 + for tag in ("w:ins", "w:del"): + elements = self.dom.getElementsByTagName(tag) + for elem in elements: + change_id = elem.getAttribute("w:id") + if change_id: + try: + max_id = max(max_id, int(change_id)) + except ValueError: + pass + return max_id + 1 + + def _ensure_w16du_namespace(self): + """Ensure w16du namespace is declared on the root element.""" + root = self.dom.documentElement + if not root.hasAttribute("xmlns:w16du"): # type: ignore + root.setAttribute( # type: ignore + "xmlns:w16du", + "http://schemas.microsoft.com/office/word/2023/wordml/word16du", + ) + + def _ensure_w16cex_namespace(self): + """Ensure w16cex namespace is declared on the root element.""" + root = self.dom.documentElement + if not root.hasAttribute("xmlns:w16cex"): # type: ignore + root.setAttribute( # type: ignore + "xmlns:w16cex", + "http://schemas.microsoft.com/office/word/2018/wordml/cex", + ) + + def _ensure_w14_namespace(self): + """Ensure w14 namespace is declared on the root element.""" + root = self.dom.documentElement + if not root.hasAttribute("xmlns:w14"): # type: ignore + root.setAttribute( # type: ignore + "xmlns:w14", + "http://schemas.microsoft.com/office/word/2010/wordml", + ) + + def _inject_attributes_to_nodes(self, nodes): + """Inject RSID, author, and date attributes into DOM nodes where applicable. + + Adds attributes to elements that support them: + - w:r: gets w:rsidR (or w:rsidDel if inside w:del) + - w:p: gets w:rsidR, w:rsidRDefault, w:rsidP, w14:paraId, w14:textId + - w:t: gets xml:space="preserve" if text has leading/trailing whitespace + - w:ins, w:del: get w:id, w:author, w:date, w16du:dateUtc + - w:comment: gets w:author, w:date, w:initials + - w16cex:commentExtensible: gets w16cex:dateUtc + + Args: + nodes: List of DOM nodes to process + """ + from datetime import datetime, timezone + + timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + + def is_inside_deletion(elem): + """Check if element is inside a w:del element.""" + parent = elem.parentNode + while parent: + if parent.nodeType == parent.ELEMENT_NODE and parent.tagName == "w:del": + return True + parent = parent.parentNode + return False + + def add_rsid_to_p(elem): + if not elem.hasAttribute("w:rsidR"): + elem.setAttribute("w:rsidR", self.rsid) + if not elem.hasAttribute("w:rsidRDefault"): + elem.setAttribute("w:rsidRDefault", self.rsid) + if not elem.hasAttribute("w:rsidP"): + elem.setAttribute("w:rsidP", self.rsid) + # Add w14:paraId and w14:textId if not present + if not elem.hasAttribute("w14:paraId"): + self._ensure_w14_namespace() + elem.setAttribute("w14:paraId", _generate_hex_id()) + if not elem.hasAttribute("w14:textId"): + self._ensure_w14_namespace() + elem.setAttribute("w14:textId", _generate_hex_id()) + + def add_rsid_to_r(elem): + # Use w:rsidDel for inside , otherwise w:rsidR + if is_inside_deletion(elem): + if not elem.hasAttribute("w:rsidDel"): + elem.setAttribute("w:rsidDel", self.rsid) + else: + if not elem.hasAttribute("w:rsidR"): + elem.setAttribute("w:rsidR", self.rsid) + + def add_tracked_change_attrs(elem): + # Auto-assign w:id if not present + if not elem.hasAttribute("w:id"): + elem.setAttribute("w:id", str(self._get_next_change_id())) + if not elem.hasAttribute("w:author"): + elem.setAttribute("w:author", self.author) + if not elem.hasAttribute("w:date"): + elem.setAttribute("w:date", timestamp) + # Add w16du:dateUtc for tracked changes (same as w:date since we generate UTC timestamps) + if elem.tagName in ("w:ins", "w:del") and not elem.hasAttribute( + "w16du:dateUtc" + ): + self._ensure_w16du_namespace() + elem.setAttribute("w16du:dateUtc", timestamp) + + def add_comment_attrs(elem): + if not elem.hasAttribute("w:author"): + elem.setAttribute("w:author", self.author) + if not elem.hasAttribute("w:date"): + elem.setAttribute("w:date", timestamp) + if not elem.hasAttribute("w:initials"): + elem.setAttribute("w:initials", self.initials) + + def add_comment_extensible_date(elem): + # Add w16cex:dateUtc for comment extensible elements + if not elem.hasAttribute("w16cex:dateUtc"): + self._ensure_w16cex_namespace() + elem.setAttribute("w16cex:dateUtc", timestamp) + + def add_xml_space_to_t(elem): + # Add xml:space="preserve" to w:t if text has leading/trailing whitespace + if ( + elem.firstChild + and elem.firstChild.nodeType == elem.firstChild.TEXT_NODE + ): + text = elem.firstChild.data + if text and (text[0].isspace() or text[-1].isspace()): + if not elem.hasAttribute("xml:space"): + elem.setAttribute("xml:space", "preserve") + + for node in nodes: + if node.nodeType != node.ELEMENT_NODE: + continue + + # Handle the node itself + if node.tagName == "w:p": + add_rsid_to_p(node) + elif node.tagName == "w:r": + add_rsid_to_r(node) + elif node.tagName == "w:t": + add_xml_space_to_t(node) + elif node.tagName in ("w:ins", "w:del"): + add_tracked_change_attrs(node) + elif node.tagName == "w:comment": + add_comment_attrs(node) + elif node.tagName == "w16cex:commentExtensible": + add_comment_extensible_date(node) + + # Process descendants (getElementsByTagName doesn't return the element itself) + for elem in node.getElementsByTagName("w:p"): + add_rsid_to_p(elem) + for elem in node.getElementsByTagName("w:r"): + add_rsid_to_r(elem) + for elem in node.getElementsByTagName("w:t"): + add_xml_space_to_t(elem) + for tag in ("w:ins", "w:del"): + for elem in node.getElementsByTagName(tag): + add_tracked_change_attrs(elem) + for elem in node.getElementsByTagName("w:comment"): + add_comment_attrs(elem) + for elem in node.getElementsByTagName("w16cex:commentExtensible"): + add_comment_extensible_date(elem) + + def replace_node(self, elem, new_content): + """Replace node with automatic attribute injection.""" + nodes = super().replace_node(elem, new_content) + self._inject_attributes_to_nodes(nodes) + return nodes + + def insert_after(self, elem, xml_content): + """Insert after with automatic attribute injection.""" + nodes = super().insert_after(elem, xml_content) + self._inject_attributes_to_nodes(nodes) + return nodes + + def insert_before(self, elem, xml_content): + """Insert before with automatic attribute injection.""" + nodes = super().insert_before(elem, xml_content) + self._inject_attributes_to_nodes(nodes) + return nodes + + def append_to(self, elem, xml_content): + """Append to with automatic attribute injection.""" + nodes = super().append_to(elem, xml_content) + self._inject_attributes_to_nodes(nodes) + return nodes + + def revert_insertion(self, elem): + """Reject an insertion by wrapping its content in a deletion. + + Wraps all runs inside w:ins in w:del, converting w:t to w:delText. + Can process a single w:ins element or a container element with multiple w:ins. + + Args: + elem: Element to process (w:ins, w:p, w:body, etc.) + + Returns: + list: List containing the processed element(s) + + Raises: + ValueError: If the element contains no w:ins elements + + Example: + # Reject a single insertion + ins = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id": "5"}) + doc["word/document.xml"].revert_insertion(ins) + + # Reject all insertions in a paragraph + para = doc["word/document.xml"].get_node(tag="w:p", line_number=42) + doc["word/document.xml"].revert_insertion(para) + """ + # Collect insertions + ins_elements = [] + if elem.tagName == "w:ins": + ins_elements.append(elem) + else: + ins_elements.extend(elem.getElementsByTagName("w:ins")) + + # Validate that there are insertions to reject + if not ins_elements: + raise ValueError( + f"revert_insertion requires w:ins elements. " + f"The provided element <{elem.tagName}> contains no insertions. " + ) + + # Process all insertions - wrap all children in w:del + for ins_elem in ins_elements: + runs = list(ins_elem.getElementsByTagName("w:r")) + if not runs: + continue + + # Create deletion wrapper + del_wrapper = self.dom.createElement("w:del") + + # Process each run + for run in runs: + # Convert w:t → w:delText and w:rsidR → w:rsidDel + if run.hasAttribute("w:rsidR"): + run.setAttribute("w:rsidDel", run.getAttribute("w:rsidR")) + run.removeAttribute("w:rsidR") + elif not run.hasAttribute("w:rsidDel"): + run.setAttribute("w:rsidDel", self.rsid) + + for t_elem in list(run.getElementsByTagName("w:t")): + del_text = self.dom.createElement("w:delText") + # Copy ALL child nodes (not just firstChild) to handle entities + while t_elem.firstChild: + del_text.appendChild(t_elem.firstChild) + for i in range(t_elem.attributes.length): + attr = t_elem.attributes.item(i) + del_text.setAttribute(attr.name, attr.value) + t_elem.parentNode.replaceChild(del_text, t_elem) + + # Move all children from ins to del wrapper + while ins_elem.firstChild: + del_wrapper.appendChild(ins_elem.firstChild) + + # Add del wrapper back to ins + ins_elem.appendChild(del_wrapper) + + # Inject attributes to the deletion wrapper + self._inject_attributes_to_nodes([del_wrapper]) + + return [elem] + + def revert_deletion(self, elem): + """Reject a deletion by re-inserting the deleted content. + + Creates w:ins elements after each w:del, copying deleted content and + converting w:delText back to w:t. + Can process a single w:del element or a container element with multiple w:del. + + Args: + elem: Element to process (w:del, w:p, w:body, etc.) + + Returns: + list: If elem is w:del, returns [elem, new_ins]. Otherwise returns [elem]. + + Raises: + ValueError: If the element contains no w:del elements + + Example: + # Reject a single deletion - returns [w:del, w:ins] + del_elem = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "3"}) + nodes = doc["word/document.xml"].revert_deletion(del_elem) + + # Reject all deletions in a paragraph - returns [para] + para = doc["word/document.xml"].get_node(tag="w:p", line_number=42) + nodes = doc["word/document.xml"].revert_deletion(para) + """ + # Collect deletions FIRST - before we modify the DOM + del_elements = [] + is_single_del = elem.tagName == "w:del" + + if is_single_del: + del_elements.append(elem) + else: + del_elements.extend(elem.getElementsByTagName("w:del")) + + # Validate that there are deletions to reject + if not del_elements: + raise ValueError( + f"revert_deletion requires w:del elements. " + f"The provided element <{elem.tagName}> contains no deletions. " + ) + + # Track created insertion (only relevant if elem is a single w:del) + created_insertion = None + + # Process all deletions - create insertions that copy the deleted content + for del_elem in del_elements: + # Clone the deleted runs and convert them to insertions + runs = list(del_elem.getElementsByTagName("w:r")) + if not runs: + continue + + # Create insertion wrapper + ins_elem = self.dom.createElement("w:ins") + + for run in runs: + # Clone the run + new_run = run.cloneNode(True) + + # Convert w:delText → w:t + for del_text in list(new_run.getElementsByTagName("w:delText")): + t_elem = self.dom.createElement("w:t") + # Copy ALL child nodes (not just firstChild) to handle entities + while del_text.firstChild: + t_elem.appendChild(del_text.firstChild) + for i in range(del_text.attributes.length): + attr = del_text.attributes.item(i) + t_elem.setAttribute(attr.name, attr.value) + del_text.parentNode.replaceChild(t_elem, del_text) + + # Update run attributes: w:rsidDel → w:rsidR + if new_run.hasAttribute("w:rsidDel"): + new_run.setAttribute("w:rsidR", new_run.getAttribute("w:rsidDel")) + new_run.removeAttribute("w:rsidDel") + elif not new_run.hasAttribute("w:rsidR"): + new_run.setAttribute("w:rsidR", self.rsid) + + ins_elem.appendChild(new_run) + + # Insert the new insertion after the deletion + nodes = self.insert_after(del_elem, ins_elem.toxml()) + + # If processing a single w:del, track the created insertion + if is_single_del and nodes: + created_insertion = nodes[0] + + # Return based on input type + if is_single_del and created_insertion: + return [elem, created_insertion] + else: + return [elem] + + @staticmethod + def suggest_paragraph(xml_content: str) -> str: + """Transform paragraph XML to add tracked change wrapping for insertion. + + Wraps runs in and adds to w:rPr in w:pPr for numbered lists. + + Args: + xml_content: XML string containing a element + + Returns: + str: Transformed XML with tracked change wrapping + """ + wrapper = f'{xml_content}' + doc = minidom.parseString(wrapper) + para = doc.getElementsByTagName("w:p")[0] + + # Ensure w:pPr exists + pPr_list = para.getElementsByTagName("w:pPr") + if not pPr_list: + pPr = doc.createElement("w:pPr") + para.insertBefore( + pPr, para.firstChild + ) if para.firstChild else para.appendChild(pPr) + else: + pPr = pPr_list[0] + + # Ensure w:rPr exists in w:pPr + rPr_list = pPr.getElementsByTagName("w:rPr") + if not rPr_list: + rPr = doc.createElement("w:rPr") + pPr.appendChild(rPr) + else: + rPr = rPr_list[0] + + # Add to w:rPr + ins_marker = doc.createElement("w:ins") + rPr.insertBefore( + ins_marker, rPr.firstChild + ) if rPr.firstChild else rPr.appendChild(ins_marker) + + # Wrap all non-pPr children in + ins_wrapper = doc.createElement("w:ins") + for child in [c for c in para.childNodes if c.nodeName != "w:pPr"]: + para.removeChild(child) + ins_wrapper.appendChild(child) + para.appendChild(ins_wrapper) + + return para.toxml() + + def suggest_deletion(self, elem): + """Mark a w:r or w:p element as deleted with tracked changes (in-place DOM manipulation). + + For w:r: wraps in , converts to , preserves w:rPr + For w:p (regular): wraps content in , converts to + For w:p (numbered list): adds to w:rPr in w:pPr, wraps content in + + Args: + elem: A w:r or w:p DOM element without existing tracked changes + + Returns: + Element: The modified element + + Raises: + ValueError: If element has existing tracked changes or invalid structure + """ + if elem.nodeName == "w:r": + # Check for existing w:delText + if elem.getElementsByTagName("w:delText"): + raise ValueError("w:r element already contains w:delText") + + # Convert w:t → w:delText + for t_elem in list(elem.getElementsByTagName("w:t")): + del_text = self.dom.createElement("w:delText") + # Copy ALL child nodes (not just firstChild) to handle entities + while t_elem.firstChild: + del_text.appendChild(t_elem.firstChild) + # Preserve attributes like xml:space + for i in range(t_elem.attributes.length): + attr = t_elem.attributes.item(i) + del_text.setAttribute(attr.name, attr.value) + t_elem.parentNode.replaceChild(del_text, t_elem) + + # Update run attributes: w:rsidR → w:rsidDel + if elem.hasAttribute("w:rsidR"): + elem.setAttribute("w:rsidDel", elem.getAttribute("w:rsidR")) + elem.removeAttribute("w:rsidR") + elif not elem.hasAttribute("w:rsidDel"): + elem.setAttribute("w:rsidDel", self.rsid) + + # Wrap in w:del + del_wrapper = self.dom.createElement("w:del") + parent = elem.parentNode + parent.insertBefore(del_wrapper, elem) + parent.removeChild(elem) + del_wrapper.appendChild(elem) + + # Inject attributes to the deletion wrapper + self._inject_attributes_to_nodes([del_wrapper]) + + return del_wrapper + + elif elem.nodeName == "w:p": + # Check for existing tracked changes + if elem.getElementsByTagName("w:ins") or elem.getElementsByTagName("w:del"): + raise ValueError("w:p element already contains tracked changes") + + # Check if it's a numbered list item + pPr_list = elem.getElementsByTagName("w:pPr") + is_numbered = pPr_list and pPr_list[0].getElementsByTagName("w:numPr") + + if is_numbered: + # Add to w:rPr in w:pPr + pPr = pPr_list[0] + rPr_list = pPr.getElementsByTagName("w:rPr") + + if not rPr_list: + rPr = self.dom.createElement("w:rPr") + pPr.appendChild(rPr) + else: + rPr = rPr_list[0] + + # Add marker + del_marker = self.dom.createElement("w:del") + rPr.insertBefore( + del_marker, rPr.firstChild + ) if rPr.firstChild else rPr.appendChild(del_marker) + + # Convert w:t → w:delText in all runs + for t_elem in list(elem.getElementsByTagName("w:t")): + del_text = self.dom.createElement("w:delText") + # Copy ALL child nodes (not just firstChild) to handle entities + while t_elem.firstChild: + del_text.appendChild(t_elem.firstChild) + # Preserve attributes like xml:space + for i in range(t_elem.attributes.length): + attr = t_elem.attributes.item(i) + del_text.setAttribute(attr.name, attr.value) + t_elem.parentNode.replaceChild(del_text, t_elem) + + # Update run attributes: w:rsidR → w:rsidDel + for run in elem.getElementsByTagName("w:r"): + if run.hasAttribute("w:rsidR"): + run.setAttribute("w:rsidDel", run.getAttribute("w:rsidR")) + run.removeAttribute("w:rsidR") + elif not run.hasAttribute("w:rsidDel"): + run.setAttribute("w:rsidDel", self.rsid) + + # Wrap all non-pPr children in + del_wrapper = self.dom.createElement("w:del") + for child in [c for c in elem.childNodes if c.nodeName != "w:pPr"]: + elem.removeChild(child) + del_wrapper.appendChild(child) + elem.appendChild(del_wrapper) + + # Inject attributes to the deletion wrapper + self._inject_attributes_to_nodes([del_wrapper]) + + return elem + + else: + raise ValueError(f"Element must be w:r or w:p, got {elem.nodeName}") + + +def _generate_hex_id() -> str: + """Generate random 8-character hex ID for para/durable IDs. + + Values are constrained to be less than 0x7FFFFFFF per OOXML spec: + - paraId must be < 0x80000000 + - durableId must be < 0x7FFFFFFF + We use the stricter constraint (0x7FFFFFFF) for both. + """ + return f"{random.randint(1, 0x7FFFFFFE):08X}" + + +def _generate_rsid() -> str: + """Generate random 8-character hex RSID.""" + return "".join(random.choices("0123456789ABCDEF", k=8)) + + +class Document: + """Manages comments in unpacked Word documents.""" + + def __init__( + self, + unpacked_dir, + rsid=None, + track_revisions=False, + author="Claude", + initials="C", + ): + """ + Initialize with path to unpacked Word document directory. + Automatically sets up comment infrastructure (people.xml, RSIDs). + + Args: + unpacked_dir: Path to unpacked DOCX directory (must contain word/ subdirectory) + rsid: Optional RSID to use for all comment elements. If not provided, one will be generated. + track_revisions: If True, enables track revisions in settings.xml (default: False) + author: Default author name for comments (default: "Claude") + initials: Default author initials for comments (default: "C") + """ + self.original_path = Path(unpacked_dir) + + if not self.original_path.exists() or not self.original_path.is_dir(): + raise ValueError(f"Directory not found: {unpacked_dir}") + + # Create temporary directory with subdirectories for unpacked content and baseline + self.temp_dir = tempfile.mkdtemp(prefix="docx_") + self.unpacked_path = Path(self.temp_dir) / "unpacked" + shutil.copytree(self.original_path, self.unpacked_path) + + # Pack original directory into temporary .docx for validation baseline (outside unpacked dir) + self.original_docx = Path(self.temp_dir) / "original.docx" + pack_document(self.original_path, self.original_docx, validate=False) + + self.word_path = self.unpacked_path / "word" + + # Generate RSID if not provided + self.rsid = rsid if rsid else _generate_rsid() + print(f"Using RSID: {self.rsid}") + + # Set default author and initials + self.author = author + self.initials = initials + + # Cache for lazy-loaded editors + self._editors = {} + + # Comment file paths + self.comments_path = self.word_path / "comments.xml" + self.comments_extended_path = self.word_path / "commentsExtended.xml" + self.comments_ids_path = self.word_path / "commentsIds.xml" + self.comments_extensible_path = self.word_path / "commentsExtensible.xml" + + # Load existing comments and determine next ID (before setup modifies files) + self.existing_comments = self._load_existing_comments() + self.next_comment_id = self._get_next_comment_id() + + # Convenient access to document.xml editor (semi-private) + self._document = self["word/document.xml"] + + # Setup tracked changes infrastructure + self._setup_tracking(track_revisions=track_revisions) + + # Add author to people.xml + self._add_author_to_people(author) + + def __getitem__(self, xml_path: str) -> DocxXMLEditor: + """ + Get or create a DocxXMLEditor for the specified XML file. + + Enables lazy-loaded editors with bracket notation: + node = doc["word/document.xml"].get_node(tag="w:p", line_number=42) + + Args: + xml_path: Relative path to XML file (e.g., "word/document.xml", "word/comments.xml") + + Returns: + DocxXMLEditor instance for the specified file + + Raises: + ValueError: If the file does not exist + + Example: + # Get node from document.xml + node = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "1"}) + + # Get node from comments.xml + comment = doc["word/comments.xml"].get_node(tag="w:comment", attrs={"w:id": "0"}) + """ + if xml_path not in self._editors: + file_path = self.unpacked_path / xml_path + if not file_path.exists(): + raise ValueError(f"XML file not found: {xml_path}") + # Use DocxXMLEditor with RSID, author, and initials for all editors + self._editors[xml_path] = DocxXMLEditor( + file_path, rsid=self.rsid, author=self.author, initials=self.initials + ) + return self._editors[xml_path] + + def add_comment(self, start, end, text: str) -> int: + """ + Add a comment spanning from one element to another. + + Args: + start: DOM element for the starting point + end: DOM element for the ending point + text: Comment content + + Returns: + The comment ID that was created + + Example: + start_node = cm.get_document_node(tag="w:del", id="1") + end_node = cm.get_document_node(tag="w:ins", id="2") + cm.add_comment(start=start_node, end=end_node, text="Explanation") + """ + comment_id = self.next_comment_id + para_id = _generate_hex_id() + durable_id = _generate_hex_id() + timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + + # Add comment ranges to document.xml immediately + self._document.insert_before(start, self._comment_range_start_xml(comment_id)) + + # If end node is a paragraph, append comment markup inside it + # Otherwise insert after it (for run-level anchors) + if end.tagName == "w:p": + self._document.append_to(end, self._comment_range_end_xml(comment_id)) + else: + self._document.insert_after(end, self._comment_range_end_xml(comment_id)) + + # Add to comments.xml immediately + self._add_to_comments_xml( + comment_id, para_id, text, self.author, self.initials, timestamp + ) + + # Add to commentsExtended.xml immediately + self._add_to_comments_extended_xml(para_id, parent_para_id=None) + + # Add to commentsIds.xml immediately + self._add_to_comments_ids_xml(para_id, durable_id) + + # Add to commentsExtensible.xml immediately + self._add_to_comments_extensible_xml(durable_id) + + # Update existing_comments so replies work + self.existing_comments[comment_id] = {"para_id": para_id} + + self.next_comment_id += 1 + return comment_id + + def reply_to_comment( + self, + parent_comment_id: int, + text: str, + ) -> int: + """ + Add a reply to an existing comment. + + Args: + parent_comment_id: The w:id of the parent comment to reply to + text: Reply text + + Returns: + The comment ID that was created for the reply + + Example: + cm.reply_to_comment(parent_comment_id=0, text="I agree with this change") + """ + if parent_comment_id not in self.existing_comments: + raise ValueError(f"Parent comment with id={parent_comment_id} not found") + + parent_info = self.existing_comments[parent_comment_id] + comment_id = self.next_comment_id + para_id = _generate_hex_id() + durable_id = _generate_hex_id() + timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + + # Add comment ranges to document.xml immediately + parent_start_elem = self._document.get_node( + tag="w:commentRangeStart", attrs={"w:id": str(parent_comment_id)} + ) + parent_ref_elem = self._document.get_node( + tag="w:commentReference", attrs={"w:id": str(parent_comment_id)} + ) + + self._document.insert_after( + parent_start_elem, self._comment_range_start_xml(comment_id) + ) + parent_ref_run = parent_ref_elem.parentNode + self._document.insert_after( + parent_ref_run, f'' + ) + self._document.insert_after( + parent_ref_run, self._comment_ref_run_xml(comment_id) + ) + + # Add to comments.xml immediately + self._add_to_comments_xml( + comment_id, para_id, text, self.author, self.initials, timestamp + ) + + # Add to commentsExtended.xml immediately (with parent) + self._add_to_comments_extended_xml( + para_id, parent_para_id=parent_info["para_id"] + ) + + # Add to commentsIds.xml immediately + self._add_to_comments_ids_xml(para_id, durable_id) + + # Add to commentsExtensible.xml immediately + self._add_to_comments_extensible_xml(durable_id) + + # Update existing_comments so replies work + self.existing_comments[comment_id] = {"para_id": para_id} + + self.next_comment_id += 1 + return comment_id + + def __del__(self): + """Clean up temporary directory on deletion.""" + if hasattr(self, "temp_dir") and Path(self.temp_dir).exists(): + shutil.rmtree(self.temp_dir) + + def validate(self) -> None: + """ + Validate the document against XSD schema and redlining rules. + + Raises: + ValueError: If validation fails. + """ + # Create validators with current state + schema_validator = DOCXSchemaValidator( + self.unpacked_path, self.original_docx, verbose=False + ) + redlining_validator = RedliningValidator( + self.unpacked_path, self.original_docx, verbose=False + ) + + # Run validations + if not schema_validator.validate(): + raise ValueError("Schema validation failed") + if not redlining_validator.validate(): + raise ValueError("Redlining validation failed") + + def save(self, destination=None, validate=True) -> None: + """ + Save all modified XML files to disk and copy to destination directory. + + This persists all changes made via add_comment() and reply_to_comment(). + + Args: + destination: Optional path to save to. If None, saves back to original directory. + validate: If True, validates document before saving (default: True). + """ + # Only ensure comment relationships and content types if comment files exist + if self.comments_path.exists(): + self._ensure_comment_relationships() + self._ensure_comment_content_types() + + # Save all modified XML files in temp directory + for editor in self._editors.values(): + editor.save() + + # Validate by default + if validate: + self.validate() + + # Copy contents from temp directory to destination (or original directory) + target_path = Path(destination) if destination else self.original_path + shutil.copytree(self.unpacked_path, target_path, dirs_exist_ok=True) + + # ==================== Private: Initialization ==================== + + def _get_next_comment_id(self): + """Get the next available comment ID.""" + if not self.comments_path.exists(): + return 0 + + editor = self["word/comments.xml"] + max_id = -1 + for comment_elem in editor.dom.getElementsByTagName("w:comment"): + comment_id = comment_elem.getAttribute("w:id") + if comment_id: + try: + max_id = max(max_id, int(comment_id)) + except ValueError: + pass + return max_id + 1 + + def _load_existing_comments(self): + """Load existing comments from files to enable replies.""" + if not self.comments_path.exists(): + return {} + + editor = self["word/comments.xml"] + existing = {} + + for comment_elem in editor.dom.getElementsByTagName("w:comment"): + comment_id = comment_elem.getAttribute("w:id") + if not comment_id: + continue + + # Find para_id from the w:p element within the comment + para_id = None + for p_elem in comment_elem.getElementsByTagName("w:p"): + para_id = p_elem.getAttribute("w14:paraId") + if para_id: + break + + if not para_id: + continue + + existing[int(comment_id)] = {"para_id": para_id} + + return existing + + # ==================== Private: Setup Methods ==================== + + def _setup_tracking(self, track_revisions=False): + """Set up comment infrastructure in unpacked directory. + + Args: + track_revisions: If True, enables track revisions in settings.xml + """ + # Create or update word/people.xml + people_file = self.word_path / "people.xml" + self._update_people_xml(people_file) + + # Update XML files + self._add_content_type_for_people(self.unpacked_path / "[Content_Types].xml") + self._add_relationship_for_people( + self.word_path / "_rels" / "document.xml.rels" + ) + + # Always add RSID to settings.xml, optionally enable trackRevisions + self._update_settings( + self.word_path / "settings.xml", track_revisions=track_revisions + ) + + def _update_people_xml(self, path): + """Create people.xml if it doesn't exist.""" + if not path.exists(): + # Copy from template + shutil.copy(TEMPLATE_DIR / "people.xml", path) + + def _add_content_type_for_people(self, path): + """Add people.xml content type to [Content_Types].xml if not already present.""" + editor = self["[Content_Types].xml"] + + if self._has_override(editor, "/word/people.xml"): + return + + # Add Override element + root = editor.dom.documentElement + override_xml = '' + editor.append_to(root, override_xml) + + def _add_relationship_for_people(self, path): + """Add people.xml relationship to document.xml.rels if not already present.""" + editor = self["word/_rels/document.xml.rels"] + + if self._has_relationship(editor, "people.xml"): + return + + root = editor.dom.documentElement + root_tag = root.tagName # type: ignore + prefix = root_tag.split(":")[0] + ":" if ":" in root_tag else "" + next_rid = editor.get_next_rid() + + # Create the relationship entry + rel_xml = f'<{prefix}Relationship Id="{next_rid}" Type="http://schemas.microsoft.com/office/2011/relationships/people" Target="people.xml"/>' + editor.append_to(root, rel_xml) + + def _update_settings(self, path, track_revisions=False): + """Add RSID and optionally enable track revisions in settings.xml. + + Args: + path: Path to settings.xml + track_revisions: If True, adds trackRevisions element + + Places elements per OOXML schema order: + - trackRevisions: early (before defaultTabStop) + - rsids: late (after compat) + """ + editor = self["word/settings.xml"] + root = editor.get_node(tag="w:settings") + prefix = root.tagName.split(":")[0] if ":" in root.tagName else "w" + + # Conditionally add trackRevisions if requested + if track_revisions: + track_revisions_exists = any( + elem.tagName == f"{prefix}:trackRevisions" + for elem in editor.dom.getElementsByTagName(f"{prefix}:trackRevisions") + ) + + if not track_revisions_exists: + track_rev_xml = f"<{prefix}:trackRevisions/>" + # Try to insert before documentProtection, defaultTabStop, or at start + inserted = False + for tag in [f"{prefix}:documentProtection", f"{prefix}:defaultTabStop"]: + elements = editor.dom.getElementsByTagName(tag) + if elements: + editor.insert_before(elements[0], track_rev_xml) + inserted = True + break + if not inserted: + # Insert as first child of settings + if root.firstChild: + editor.insert_before(root.firstChild, track_rev_xml) + else: + editor.append_to(root, track_rev_xml) + + # Always check if rsids section exists + rsids_elements = editor.dom.getElementsByTagName(f"{prefix}:rsids") + + if not rsids_elements: + # Add new rsids section + rsids_xml = f'''<{prefix}:rsids> + <{prefix}:rsidRoot {prefix}:val="{self.rsid}"/> + <{prefix}:rsid {prefix}:val="{self.rsid}"/> +''' + + # Try to insert after compat, before clrSchemeMapping, or before closing tag + inserted = False + compat_elements = editor.dom.getElementsByTagName(f"{prefix}:compat") + if compat_elements: + editor.insert_after(compat_elements[0], rsids_xml) + inserted = True + + if not inserted: + clr_elements = editor.dom.getElementsByTagName( + f"{prefix}:clrSchemeMapping" + ) + if clr_elements: + editor.insert_before(clr_elements[0], rsids_xml) + inserted = True + + if not inserted: + editor.append_to(root, rsids_xml) + else: + # Check if this rsid already exists + rsids_elem = rsids_elements[0] + rsid_exists = any( + elem.getAttribute(f"{prefix}:val") == self.rsid + for elem in rsids_elem.getElementsByTagName(f"{prefix}:rsid") + ) + + if not rsid_exists: + rsid_xml = f'<{prefix}:rsid {prefix}:val="{self.rsid}"/>' + editor.append_to(rsids_elem, rsid_xml) + + # ==================== Private: XML File Creation ==================== + + def _add_to_comments_xml( + self, comment_id, para_id, text, author, initials, timestamp + ): + """Add a single comment to comments.xml.""" + if not self.comments_path.exists(): + shutil.copy(TEMPLATE_DIR / "comments.xml", self.comments_path) + + editor = self["word/comments.xml"] + root = editor.get_node(tag="w:comments") + + escaped_text = ( + text.replace("&", "&").replace("<", "<").replace(">", ">") + ) + # Note: w:rsidR, w:rsidRDefault, w:rsidP on w:p, w:rsidR on w:r, + # and w:author, w:date, w:initials on w:comment are automatically added by DocxXMLEditor + comment_xml = f''' + + + {escaped_text} + +''' + editor.append_to(root, comment_xml) + + def _add_to_comments_extended_xml(self, para_id, parent_para_id): + """Add a single comment to commentsExtended.xml.""" + if not self.comments_extended_path.exists(): + shutil.copy( + TEMPLATE_DIR / "commentsExtended.xml", self.comments_extended_path + ) + + editor = self["word/commentsExtended.xml"] + root = editor.get_node(tag="w15:commentsEx") + + if parent_para_id: + xml = f'' + else: + xml = f'' + editor.append_to(root, xml) + + def _add_to_comments_ids_xml(self, para_id, durable_id): + """Add a single comment to commentsIds.xml.""" + if not self.comments_ids_path.exists(): + shutil.copy(TEMPLATE_DIR / "commentsIds.xml", self.comments_ids_path) + + editor = self["word/commentsIds.xml"] + root = editor.get_node(tag="w16cid:commentsIds") + + xml = f'' + editor.append_to(root, xml) + + def _add_to_comments_extensible_xml(self, durable_id): + """Add a single comment to commentsExtensible.xml.""" + if not self.comments_extensible_path.exists(): + shutil.copy( + TEMPLATE_DIR / "commentsExtensible.xml", self.comments_extensible_path + ) + + editor = self["word/commentsExtensible.xml"] + root = editor.get_node(tag="w16cex:commentsExtensible") + + xml = f'' + editor.append_to(root, xml) + + # ==================== Private: XML Fragments ==================== + + def _comment_range_start_xml(self, comment_id): + """Generate XML for comment range start.""" + return f'' + + def _comment_range_end_xml(self, comment_id): + """Generate XML for comment range end with reference run. + + Note: w:rsidR is automatically added by DocxXMLEditor. + """ + return f''' + + + +''' + + def _comment_ref_run_xml(self, comment_id): + """Generate XML for comment reference run. + + Note: w:rsidR is automatically added by DocxXMLEditor. + """ + return f''' + + +''' + + # ==================== Private: Metadata Updates ==================== + + def _has_relationship(self, editor, target): + """Check if a relationship with given target exists.""" + for rel_elem in editor.dom.getElementsByTagName("Relationship"): + if rel_elem.getAttribute("Target") == target: + return True + return False + + def _has_override(self, editor, part_name): + """Check if an override with given part name exists.""" + for override_elem in editor.dom.getElementsByTagName("Override"): + if override_elem.getAttribute("PartName") == part_name: + return True + return False + + def _has_author(self, editor, author): + """Check if an author already exists in people.xml.""" + for person_elem in editor.dom.getElementsByTagName("w15:person"): + if person_elem.getAttribute("w15:author") == author: + return True + return False + + def _add_author_to_people(self, author): + """Add author to people.xml (called during initialization).""" + people_path = self.word_path / "people.xml" + + # people.xml should already exist from _setup_tracking + if not people_path.exists(): + raise ValueError("people.xml should exist after _setup_tracking") + + editor = self["word/people.xml"] + root = editor.get_node(tag="w15:people") + + # Check if author already exists + if self._has_author(editor, author): + return + + # Add author with proper XML escaping to prevent injection + escaped_author = html.escape(author, quote=True) + person_xml = f''' + +''' + editor.append_to(root, person_xml) + + def _ensure_comment_relationships(self): + """Ensure word/_rels/document.xml.rels has comment relationships.""" + editor = self["word/_rels/document.xml.rels"] + + if self._has_relationship(editor, "comments.xml"): + return + + root = editor.dom.documentElement + root_tag = root.tagName # type: ignore + prefix = root_tag.split(":")[0] + ":" if ":" in root_tag else "" + next_rid_num = int(editor.get_next_rid()[3:]) + + # Add relationship elements + rels = [ + ( + next_rid_num, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", + "comments.xml", + ), + ( + next_rid_num + 1, + "http://schemas.microsoft.com/office/2011/relationships/commentsExtended", + "commentsExtended.xml", + ), + ( + next_rid_num + 2, + "http://schemas.microsoft.com/office/2016/09/relationships/commentsIds", + "commentsIds.xml", + ), + ( + next_rid_num + 3, + "http://schemas.microsoft.com/office/2018/08/relationships/commentsExtensible", + "commentsExtensible.xml", + ), + ] + + for rel_id, rel_type, target in rels: + rel_xml = f'<{prefix}Relationship Id="rId{rel_id}" Type="{rel_type}" Target="{target}"/>' + editor.append_to(root, rel_xml) + + def _ensure_comment_content_types(self): + """Ensure [Content_Types].xml has comment content types.""" + editor = self["[Content_Types].xml"] + + if self._has_override(editor, "/word/comments.xml"): + return + + root = editor.dom.documentElement + + # Add Override elements + overrides = [ + ( + "/word/comments.xml", + "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml", + ), + ( + "/word/commentsExtended.xml", + "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml", + ), + ( + "/word/commentsIds.xml", + "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsIds+xml", + ), + ( + "/word/commentsExtensible.xml", + "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtensible+xml", + ), + ] + + for part_name, content_type in overrides: + override_xml = ( + f'' + ) + editor.append_to(root, override_xml) diff --git a/skills/docx/scripts/templates/comments.xml b/skills/docx/scripts/templates/comments.xml new file mode 100644 index 0000000..b5dace0 --- /dev/null +++ b/skills/docx/scripts/templates/comments.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/skills/docx/scripts/templates/commentsExtended.xml b/skills/docx/scripts/templates/commentsExtended.xml new file mode 100644 index 0000000..b4cf23e --- /dev/null +++ b/skills/docx/scripts/templates/commentsExtended.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/skills/docx/scripts/templates/commentsExtensible.xml b/skills/docx/scripts/templates/commentsExtensible.xml new file mode 100644 index 0000000..e32a05e --- /dev/null +++ b/skills/docx/scripts/templates/commentsExtensible.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/skills/docx/scripts/templates/commentsIds.xml b/skills/docx/scripts/templates/commentsIds.xml new file mode 100644 index 0000000..d04bc8e --- /dev/null +++ b/skills/docx/scripts/templates/commentsIds.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/skills/docx/scripts/templates/people.xml b/skills/docx/scripts/templates/people.xml new file mode 100644 index 0000000..a839caf --- /dev/null +++ b/skills/docx/scripts/templates/people.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/skills/docx/scripts/utilities.py b/skills/docx/scripts/utilities.py new file mode 100755 index 0000000..d92dae6 --- /dev/null +++ b/skills/docx/scripts/utilities.py @@ -0,0 +1,374 @@ +#!/usr/bin/env python3 +""" +Utilities for editing OOXML documents. + +This module provides XMLEditor, a tool for manipulating XML files with support for +line-number-based node finding and DOM manipulation. Each element is automatically +annotated with its original line and column position during parsing. + +Example usage: + editor = XMLEditor("document.xml") + + # Find node by line number or range + elem = editor.get_node(tag="w:r", line_number=519) + elem = editor.get_node(tag="w:p", line_number=range(100, 200)) + + # Find node by text content + elem = editor.get_node(tag="w:p", contains="specific text") + + # Find node by attributes + elem = editor.get_node(tag="w:r", attrs={"w:id": "target"}) + + # Combine filters + elem = editor.get_node(tag="w:p", line_number=range(1, 50), contains="text") + + # Replace, insert, or manipulate + new_elem = editor.replace_node(elem, "new text") + editor.insert_after(new_elem, "more") + + # Save changes + editor.save() +""" + +import html +from pathlib import Path +from typing import Optional, Union + +import defusedxml.minidom +import defusedxml.sax + + +class XMLEditor: + """ + Editor for manipulating OOXML XML files with line-number-based node finding. + + This class parses XML files and tracks the original line and column position + of each element. This enables finding nodes by their line number in the original + file, which is useful when working with Read tool output. + + Attributes: + xml_path: Path to the XML file being edited + encoding: Detected encoding of the XML file ('ascii' or 'utf-8') + dom: Parsed DOM tree with parse_position attributes on elements + """ + + def __init__(self, xml_path): + """ + Initialize with path to XML file and parse with line number tracking. + + Args: + xml_path: Path to XML file to edit (str or Path) + + Raises: + ValueError: If the XML file does not exist + """ + self.xml_path = Path(xml_path) + if not self.xml_path.exists(): + raise ValueError(f"XML file not found: {xml_path}") + + with open(self.xml_path, "rb") as f: + header = f.read(200).decode("utf-8", errors="ignore") + self.encoding = "ascii" if 'encoding="ascii"' in header else "utf-8" + + parser = _create_line_tracking_parser() + self.dom = defusedxml.minidom.parse(str(self.xml_path), parser) + + def get_node( + self, + tag: str, + attrs: Optional[dict[str, str]] = None, + line_number: Optional[Union[int, range]] = None, + contains: Optional[str] = None, + ): + """ + Get a DOM element by tag and identifier. + + Finds an element by either its line number in the original file or by + matching attribute values. Exactly one match must be found. + + Args: + tag: The XML tag name (e.g., "w:del", "w:ins", "w:r") + attrs: Dictionary of attribute name-value pairs to match (e.g., {"w:id": "1"}) + line_number: Line number (int) or line range (range) in original XML file (1-indexed) + contains: Text string that must appear in any text node within the element. + Supports both entity notation (“) and Unicode characters (\u201c). + + Returns: + defusedxml.minidom.Element: The matching DOM element + + Raises: + ValueError: If node not found or multiple matches found + + Example: + elem = editor.get_node(tag="w:r", line_number=519) + elem = editor.get_node(tag="w:r", line_number=range(100, 200)) + elem = editor.get_node(tag="w:del", attrs={"w:id": "1"}) + elem = editor.get_node(tag="w:p", attrs={"w14:paraId": "12345678"}) + elem = editor.get_node(tag="w:commentRangeStart", attrs={"w:id": "0"}) + elem = editor.get_node(tag="w:p", contains="specific text") + elem = editor.get_node(tag="w:t", contains="“Agreement") # Entity notation + elem = editor.get_node(tag="w:t", contains="\u201cAgreement") # Unicode character + """ + matches = [] + for elem in self.dom.getElementsByTagName(tag): + # Check line_number filter + if line_number is not None: + parse_pos = getattr(elem, "parse_position", (None,)) + elem_line = parse_pos[0] + + # Handle both single line number and range + if isinstance(line_number, range): + if elem_line not in line_number: + continue + else: + if elem_line != line_number: + continue + + # Check attrs filter + if attrs is not None: + if not all( + elem.getAttribute(attr_name) == attr_value + for attr_name, attr_value in attrs.items() + ): + continue + + # Check contains filter + if contains is not None: + elem_text = self._get_element_text(elem) + # Normalize the search string: convert HTML entities to Unicode characters + # This allows searching for both "“Rowan" and ""Rowan" + normalized_contains = html.unescape(contains) + if normalized_contains not in elem_text: + continue + + # If all applicable filters passed, this is a match + matches.append(elem) + + if not matches: + # Build descriptive error message + filters = [] + if line_number is not None: + line_str = ( + f"lines {line_number.start}-{line_number.stop - 1}" + if isinstance(line_number, range) + else f"line {line_number}" + ) + filters.append(f"at {line_str}") + if attrs is not None: + filters.append(f"with attributes {attrs}") + if contains is not None: + filters.append(f"containing '{contains}'") + + filter_desc = " ".join(filters) if filters else "" + base_msg = f"Node not found: <{tag}> {filter_desc}".strip() + + # Add helpful hint based on filters used + if contains: + hint = "Text may be split across elements or use different wording." + elif line_number: + hint = "Line numbers may have changed if document was modified." + elif attrs: + hint = "Verify attribute values are correct." + else: + hint = "Try adding filters (attrs, line_number, or contains)." + + raise ValueError(f"{base_msg}. {hint}") + if len(matches) > 1: + raise ValueError( + f"Multiple nodes found: <{tag}>. " + f"Add more filters (attrs, line_number, or contains) to narrow the search." + ) + return matches[0] + + def _get_element_text(self, elem): + """ + Recursively extract all text content from an element. + + Skips text nodes that contain only whitespace (spaces, tabs, newlines), + which typically represent XML formatting rather than document content. + + Args: + elem: defusedxml.minidom.Element to extract text from + + Returns: + str: Concatenated text from all non-whitespace text nodes within the element + """ + text_parts = [] + for node in elem.childNodes: + if node.nodeType == node.TEXT_NODE: + # Skip whitespace-only text nodes (XML formatting) + if node.data.strip(): + text_parts.append(node.data) + elif node.nodeType == node.ELEMENT_NODE: + text_parts.append(self._get_element_text(node)) + return "".join(text_parts) + + def replace_node(self, elem, new_content): + """ + Replace a DOM element with new XML content. + + Args: + elem: defusedxml.minidom.Element to replace + new_content: String containing XML to replace the node with + + Returns: + List[defusedxml.minidom.Node]: All inserted nodes + + Example: + new_nodes = editor.replace_node(old_elem, "text") + """ + parent = elem.parentNode + nodes = self._parse_fragment(new_content) + for node in nodes: + parent.insertBefore(node, elem) + parent.removeChild(elem) + return nodes + + def insert_after(self, elem, xml_content): + """ + Insert XML content after a DOM element. + + Args: + elem: defusedxml.minidom.Element to insert after + xml_content: String containing XML to insert + + Returns: + List[defusedxml.minidom.Node]: All inserted nodes + + Example: + new_nodes = editor.insert_after(elem, "text") + """ + parent = elem.parentNode + next_sibling = elem.nextSibling + nodes = self._parse_fragment(xml_content) + for node in nodes: + if next_sibling: + parent.insertBefore(node, next_sibling) + else: + parent.appendChild(node) + return nodes + + def insert_before(self, elem, xml_content): + """ + Insert XML content before a DOM element. + + Args: + elem: defusedxml.minidom.Element to insert before + xml_content: String containing XML to insert + + Returns: + List[defusedxml.minidom.Node]: All inserted nodes + + Example: + new_nodes = editor.insert_before(elem, "text") + """ + parent = elem.parentNode + nodes = self._parse_fragment(xml_content) + for node in nodes: + parent.insertBefore(node, elem) + return nodes + + def append_to(self, elem, xml_content): + """ + Append XML content as a child of a DOM element. + + Args: + elem: defusedxml.minidom.Element to append to + xml_content: String containing XML to append + + Returns: + List[defusedxml.minidom.Node]: All inserted nodes + + Example: + new_nodes = editor.append_to(elem, "text") + """ + nodes = self._parse_fragment(xml_content) + for node in nodes: + elem.appendChild(node) + return nodes + + def get_next_rid(self): + """Get the next available rId for relationships files.""" + max_id = 0 + for rel_elem in self.dom.getElementsByTagName("Relationship"): + rel_id = rel_elem.getAttribute("Id") + if rel_id.startswith("rId"): + try: + max_id = max(max_id, int(rel_id[3:])) + except ValueError: + pass + return f"rId{max_id + 1}" + + def save(self): + """ + Save the edited XML back to the file. + + Serializes the DOM tree and writes it back to the original file path, + preserving the original encoding (ascii or utf-8). + """ + content = self.dom.toxml(encoding=self.encoding) + self.xml_path.write_bytes(content) + + def _parse_fragment(self, xml_content): + """ + Parse XML fragment and return list of imported nodes. + + Args: + xml_content: String containing XML fragment + + Returns: + List of defusedxml.minidom.Node objects imported into this document + + Raises: + AssertionError: If fragment contains no element nodes + """ + # Extract namespace declarations from the root document element + root_elem = self.dom.documentElement + namespaces = [] + if root_elem and root_elem.attributes: + for i in range(root_elem.attributes.length): + attr = root_elem.attributes.item(i) + if attr.name.startswith("xmlns"): # type: ignore + namespaces.append(f'{attr.name}="{attr.value}"') # type: ignore + + ns_decl = " ".join(namespaces) + wrapper = f"{xml_content}" + fragment_doc = defusedxml.minidom.parseString(wrapper) + nodes = [ + self.dom.importNode(child, deep=True) + for child in fragment_doc.documentElement.childNodes # type: ignore + ] + elements = [n for n in nodes if n.nodeType == n.ELEMENT_NODE] + assert elements, "Fragment must contain at least one element" + return nodes + + +def _create_line_tracking_parser(): + """ + Create a SAX parser that tracks line and column numbers for each element. + + Monkey patches the SAX content handler to store the current line and column + position from the underlying expat parser onto each element as a parse_position + attribute (line, column) tuple. + + Returns: + defusedxml.sax.xmlreader.XMLReader: Configured SAX parser + """ + + def set_content_handler(dom_handler): + def startElementNS(name, tagName, attrs): + orig_start_cb(name, tagName, attrs) + cur_elem = dom_handler.elementStack[-1] + cur_elem.parse_position = ( + parser._parser.CurrentLineNumber, # type: ignore + parser._parser.CurrentColumnNumber, # type: ignore + ) + + orig_start_cb = dom_handler.startElementNS + dom_handler.startElementNS = startElementNS + orig_set_content_handler(dom_handler) + + parser = defusedxml.sax.make_parser() + orig_set_content_handler = parser.setContentHandler + parser.setContentHandler = set_content_handler # type: ignore + return parser diff --git a/skills/drafts-manager/SKILL.md b/skills/drafts-manager/SKILL.md new file mode 100644 index 0000000..aa8dd58 --- /dev/null +++ b/skills/drafts-manager/SKILL.md @@ -0,0 +1,433 @@ +--- +name: drafts-manager +description: Triage Drafts inbox and route notes to OmniFocus tasks or Obsidian documents +triggers: + - "triage drafts" + - "process drafts" + - "check drafts" + - "what's in drafts" + - "drafts inbox" + - "clean up drafts" + - "export drafts" +allowed-tools: Read, Bash, Write +version: 0.1.0 +--- + +# Drafts Manager Skill + +Triage the Drafts inbox using a hybrid AI + human confirmation workflow. Routes content to OmniFocus (tasks) or Obsidian (notes) based on content analysis. + +## When to Activate + +Use this skill when user wants to: +- Triage or process their Drafts inbox +- Route notes to OmniFocus or Obsidian +- Check what's captured in Drafts +- Clean up old drafts + +## Architecture + +**Two-Phase Hybrid Triage:** + +1. **Export & Analyze** - Drafts exports inbox → Geoffrey analyzes → presents suggestions +2. **Confirm & Process** - User confirms routing → Drafts processes each draft → archives + +``` +┌─────────┐ URL ┌─────────┐ JSON ┌─────────┐ Table ┌──────┐ +│Geoffrey │ ────► │ Drafts │ ─────► │Geoffrey │ ──────► │ User │ +│ trigger │ │ export │ │ analyze │ │review│ +└─────────┘ └─────────┘ └─────────┘ └──┬───┘ + │ + Confirmed + │ +┌─────────┐ URL ┌─────────┐ Routes ┌──────────┐ ┌───▼────┐ +│Geoffrey │ ────► │ Drafts │ ───────► │OmniFocus │ │Process │ +│ trigger │ │ process │ │ Obsidian │ │ list │ +└─────────┘ └────┬────┘ └──────────┘ └────────┘ + │ + Archives +``` + +## Available Scripts + +Scripts are in `./scripts/` directory. Run via: +```bash +bun ./scripts/script-name.js +``` + +### trigger_export.js + +Triggers the Drafts "Geoffrey Export Inbox" action via URL scheme. + +**Output:** Path to exported JSON file + +**Use when:** Starting triage + +### trigger_process.js + +Triggers the Drafts "Geoffrey Process Draft" action with routing instructions. + +**Parameters:** uuid, destination, project, tags, folder + +**Use when:** Processing confirmed drafts + +## Required Drafts Actions + +**IMPORTANT:** User must install these Drafts actions (found in `./actions/`): + +### Geoffrey Export Inbox + +Exports all inbox drafts to a JSON file for Geoffrey to analyze. + +**Location:** `~/Library/Mobile Documents/iCloud~com~agiletortoise~Drafts5/Documents/geoffrey-export.json` + +**Output format:** +```json +{ + "exported": "2025-11-23T10:30:00Z", + "count": 5, + "drafts": [ + { + "uuid": "ABC123", + "title": "First line of draft", + "content": "Full content...", + "tags": ["inbox"], + "createdAt": "2025-11-22T14:00:00Z", + "modifiedAt": "2025-11-22T14:00:00Z", + "isFlagged": false + } + ] +} +``` + +### Geoffrey Process Draft + +Processes a single draft based on routing instructions from URL parameters. + +**URL Parameters:** +- `uuid` - Draft to process +- `destination` - "omnifocus", "obsidian", "archive", or "trash" +- `project` - OmniFocus project (if destination=omnifocus) +- `tags` - Comma-separated tags (if destination=omnifocus) +- `dueDate` - Due date (if destination=omnifocus) +- `folder` - Obsidian folder (if destination=obsidian) + +## Content Analysis Rules + +When analyzing drafts, look for these signals: + +### Route to OmniFocus (Task) + +**Signals:** +- Starts with action verb: "call", "email", "buy", "schedule", "review", "check" +- Contains: "todo", "task", "@due", "@defer" +- Short (< 50 words) +- Contains person names +- Shopping lists or errands + +**Apply omnifocus-manager routing rules for project/tag assignment** + +### Route to Obsidian (Note) + +**Signals:** +- Longer content (> 100 words) +- Meeting notes: "meeting with", "discussed", "attendees" +- Ideas/brainstorms: "idea:", "thought:", "what if" +- Reference material: links, quotes, research +- Journal entries: "today I", feelings, reflections + +### Archive in Drafts + +**Signals:** +- Reference that may be needed again +- Snippets of code or text +- Temporary notes that are now done + +### Delete (Trash) + +**Signals:** +- Empty or nearly empty +- Test/scratch content +- Duplicates +- Outdated info no longer needed + +## Obsidian Routing Rules + +| Content Type | Folder | Frontmatter | +|--------------|--------|-------------| +| Meeting notes | `Meetings/` | date, attendees, topics | +| Ideas/brainstorms | `Geoffrey/Inbox/` | tags, created | +| Research | `Reference/` | source, tags, related | +| Journal | `Journal/` | date | +| General notes | `Geoffrey/Inbox/` | tags, created | + +**Frontmatter template:** +```yaml +--- +created: {{date}} +source: drafts +tags: [from-drafts] +related: [] +--- +``` + +## Main Workflow: Triage Drafts + +### Phase 1: Export & Analyze + +1. **Trigger export:** + ```bash + open "drafts://x-callback-url/runAction?action=Geoffrey%20Export%20Inbox" + ``` + +2. **Wait for export file** (2-3 seconds) + +3. **Read exported JSON:** + ```bash + cat ~/Library/Mobile\ Documents/iCloud~com~agiletortoise~Drafts5/Documents/geoffrey-export.json + ``` + +4. **Analyze each draft** using content signals above + +5. **Present suggestions table:** + ```markdown + ## Drafts Inbox Triage + + Found **5 drafts** to process: + + | # | Title | Suggestion | Destination | Details | + |---|-------|------------|-------------|---------| + | 1 | Call John about... | Task | OmniFocus | Project: Meetings, Tags: John, Follow Up | + | 2 | Meeting notes 11/22 | Note | Obsidian | Folder: Meetings/ | + | 3 | [empty] | Delete | Trash | Empty draft | + | 4 | Shopping list | Task | OmniFocus | Project: Single Actions, Tags: Chores | + | 5 | Idea for app... | Note | Obsidian | Folder: Geoffrey/Inbox/ | + + **Questions:** + - #4: Should this go to a specific store location tag? + + Which numbers need changes? (Or type "process all" to confirm) + ``` + +### Phase 2: Process & Archive + +1. **For each confirmed draft**, trigger process action: + ```bash + # OmniFocus task + open "drafts://x-callback-url/runAction?action=Geoffrey%20Process%20Draft&uuid=ABC123&destination=omnifocus&project=Meetings&tags=John,Follow%20Up&dueDate=2025-11-30" + + # Obsidian note + open "drafts://x-callback-url/runAction?action=Geoffrey%20Process%20Draft&uuid=DEF456&destination=obsidian&folder=Meetings" + + # Archive + open "drafts://x-callback-url/runAction?action=Geoffrey%20Process%20Draft&uuid=GHI789&destination=archive" + + # Delete + open "drafts://x-callback-url/runAction?action=Geoffrey%20Process%20Draft&uuid=JKL012&destination=trash" + ``` + +2. **Report results:** + ```markdown + ## Summary + Processed 5 drafts from inbox + + ## Actions + - 2 tasks created in OmniFocus + - 2 notes saved to Obsidian + - 1 draft deleted + + ## Status + ✅ Complete + + ## Next Steps + - Review tasks in OmniFocus inbox + - Check Obsidian notes in Geoffrey/Inbox/ + ``` + +## Error Handling + +**Drafts not running:** +``` +Status: ❌ Failed +Error: Drafts app is not running. Please open Drafts and try again. +``` + +**Action not installed:** +``` +Status: ❌ Failed +Error: Drafts action "Geoffrey Export Inbox" not found. +Please install from: skills/drafts-manager/actions/ +``` + +**Export file not found:** +``` +Status: ⚠️ Partial +Error: Export file not created. Drafts may have timed out. +Try running the action manually in Drafts. +``` + +**OmniFocus not running:** +``` +Status: ⚠️ Partial +Warning: OmniFocus not running. Task creation may have failed. +Please verify tasks were created. +``` + +## Installation + +### 1. Install Drafts Actions + +Import the action files from `./actions/`: + +**Option A: Import from file** +1. Open Drafts +2. Go to Actions → Manage Actions +3. Import from `actions/geoffrey-export-inbox.draftsAction` +4. Import from `actions/geoffrey-process-draft.draftsAction` + +**Option B: Create manually** +1. Open Drafts +2. Create new action "Geoffrey Export Inbox" +3. Add Script step with code from `actions/geoffrey-export-inbox.js` +4. Repeat for "Geoffrey Process Draft" + +### 2. Verify Installation + +Run: `open "drafts://x-callback-url/runAction?action=Geoffrey%20Export%20Inbox"` + +Check for export file at: +`~/Library/Mobile Documents/iCloud~com~agiletortoise~Drafts5/Documents/geoffrey-export.json` + +## Tips for Best Results + +### Tagging in Drafts + +Use these tags for manual pre-routing: +- `task` - Force route to OmniFocus +- `note` - Force route to Obsidian +- `archive` - Keep in Drafts archive +- `delete` - Trash without review + +### Quick Capture Patterns + +When capturing to Drafts, these patterns help AI routing: +- Start tasks with verbs: "Call", "Email", "Buy" +- Start notes with context: "Meeting:", "Idea:", "Note:" +- Use @ for OmniFocus hints: "@due(tomorrow)", "@project(Work)" + +### Regular Triage + +Best practice: Triage Drafts daily to keep inbox small +- Morning: Process yesterday's captures +- Evening: Quick review of day's notes + +## Learned Routing Patterns + +These patterns were learned through actual triage sessions with the user. + +### Content Type → Destination + +| Content Type | Destination | Obsidian Folder | OmniFocus Details | +|--------------|-------------|-----------------|-------------------| +| Meeting notes | Obsidian | `Meetings/2025/` | - | +| Conference notes | Obsidian | `Meetings/2025/` | - | +| Development roadmap | Obsidian | `Work/[Project]/Roadmap.md` | Format as checklist | +| API keys/credentials | **Delete** | - | Security risk | +| Error logs/JSON junk | **Delete** | - | Cruft | +| Random passwords | **Delete** | - | Cruft | +| Contact info | Contacts app | - | Also create follow-up task | +| Book recommendations | OmniFocus | - | Tags: Reading | +| Gift ideas | OmniFocus | - | Tags: Chores, Shopping | +| Action items from meetings | OmniFocus | - | Tags: Follow Up | +| Reference links (AI, UDL) | Obsidian | `Reference/` | - | +| Personal project ideas | OmniFocus | - | Tags: Coding | +| Presentation schedules | Obsidian | `Work/Presentations/` | Future dates → tasks | +| Survey links | OmniFocus | - | Include links in notes | + +### Signals for Each Destination + +**→ OmniFocus Task:** +- Starts with action verbs: "Submit", "Call", "Email", "Build", "Add" +- Contains due date context: "first week of December", "by end of year" +- Travel approvals, surveys to send, podcasts to record +- Book to read, thing to buy, project to build +- Multiple action items → single task with checklist in notes + +**→ Obsidian Note:** +- Meeting notes (look for date, attendees, discussion points) +- Conference notes (look for session titles, speakers, links) +- Development docs with code/commands (wrap in code blocks) +- Reference material with links to external resources +- Topic brainstorms and idea lists + +**→ Contacts App:** +- Contains name + phone/email +- Create contact AND follow-up task if there's an action + +**→ Delete:** +- Empty or nearly empty +- JSON/error logs +- API keys (security) +- Random strings/passwords +- Test data that's no longer needed + +**→ Archive in Drafts:** +- Outdated but potentially useful later +- Reference that may be needed again + +### Project/Folder Mappings + +**Obsidian Folders:** +- `Meetings/2025/` - All meeting and conference notes +- `Work/AI-Studio/` - AI Studio development docs +- `Work/Jocular-Kangaroo/` - Jocular Kangaroo project +- `Work/Presentations/` - Presentation archives +- `Geoffrey/` - Geoffrey roadmap and ideas +- `Reference/` - Reference materials and links + +**OmniFocus Projects (go to Inbox if not found):** +- CoSN Work - CoSN-related tasks +- Meetings - Follow-ups with people +- Research for Future Plans - Books, research tasks + +**OmniFocus Tags:** +- Follow Up - Tasks requiring follow-up +- Reading - Books to read +- Chores - Shopping, errands +- Coding - Development tasks +- Geoffrey - AI-assistable tasks +- Email - Tasks requiring email + +### Special Handling + +**Multi-item notes:** +- If note contains multiple distinct items, either: + - Create single task with items as checklist in notes + - Split into separate tasks (ask user preference) + +**Development roadmaps:** +- Format as Obsidian file with checkboxes +- Use `- [ ]` for pending items +- Use `- [x]` for completed items +- Include code blocks for commands + +**Sensitive data:** +- API keys → Delete immediately +- Student investigation data → Archive carefully, don't expose +- Credentials → Delete or move to secure storage + +**Contact + Task pattern:** +- Add to Contacts app via add_contact.js +- Create follow-up task with contact details in notes +- Example: "Send maps to Kim Crowder" with email in notes + +## Future Enhancements + +- [ ] Batch processing without confirmation for tagged drafts +- [ ] Smart date extraction from draft content +- [ ] Template matching for common note types +- [ ] Sync with omnifocus-manager tag hierarchy +- [ ] Obsidian template application +- [ ] Draft content search/query +- [ ] Auto-detect project roadmaps and format as checklists +- [ ] Recognize CoSN, ACPE, Kiwanis contexts for project routing diff --git a/skills/drafts-manager/actions/README.md b/skills/drafts-manager/actions/README.md new file mode 100644 index 0000000..b5124e3 --- /dev/null +++ b/skills/drafts-manager/actions/README.md @@ -0,0 +1,124 @@ +# Installing Drafts Actions + +These actions must be installed in Drafts before the drafts-manager skill can work. + +## Quick Install + +### Geoffrey Export Inbox + +1. Open Drafts on your Mac +2. Go to **Drafts → Settings → Actions → Manage Actions** +3. Click the **+** button to create a new action +4. Set the name to: `Geoffrey Export Inbox` +5. Click **Steps** → Add **Script** step +6. Copy the entire contents of `geoffrey-export-inbox.js` into the script editor +7. Click **Done** to save + +### Geoffrey Process Draft + +1. Create another new action +2. Set the name to: `Geoffrey Process Draft` +3. Click **Steps** → Add **Script** step +4. Copy the entire contents of `geoffrey-process-draft.js` into the script editor +5. **Important:** Click the gear icon on the action and set: + - After Success: **Do Nothing** (don't archive the draft - the script handles this) +6. Click **Done** to save + +## Verification + +Test that the export action works: + +```bash +open "drafts://x-callback-url/runAction?action=Geoffrey%20Export%20Inbox" +``` + +Check for the export file: + +```bash +ls -la ~/Library/Mobile\ Documents/iCloud~com~agiletortoise~Drafts5/Documents/geoffrey-export.json +``` + +If the file exists and was recently modified, the action is working. + +## Troubleshooting + +### "Action not found" error + +- Make sure the action names match exactly: + - `Geoffrey Export Inbox` + - `Geoffrey Process Draft` +- Check for extra spaces or different capitalization + +### Export file not created + +- Open Drafts manually and run the action from the action list +- Check for script errors in Drafts' action log + +### OmniFocus tasks not created + +- Make sure OmniFocus is running +- The OmniFocus URL scheme needs the app to be open + +### Obsidian notes not created + +- Make sure Obsidian is running +- Verify the vault name is "Personal_Notes" +- Check that the folder path exists + +## Action Configuration + +### Template Tags + +The process action uses Drafts template tags to receive parameters. When called via URL: + +``` +drafts://x-callback-url/runAction?action=Geoffrey%20Process%20Draft&uuid=ABC&destination=omnifocus +``` + +The parameters become available as template tags in the script. + +### Customization + +To change the Obsidian vault path, edit this line in `geoffrey-process-draft.js`: + +```javascript +let obsidianVault = "/Users/hagelk/Library/Mobile Documents/iCloud~md~obsidian/Documents/Personal_Notes"; +``` + +To change the default Obsidian folder, edit: + +```javascript +let folder = draft.getTemplateTag("folder") || "Geoffrey/Inbox"; +``` + +## URL Scheme Reference + +### Export + +``` +drafts://x-callback-url/runAction?action=Geoffrey%20Export%20Inbox +``` + +### Process to OmniFocus + +``` +drafts://x-callback-url/runAction?action=Geoffrey%20Process%20Draft&uuid=UUID&destination=omnifocus&project=Project&tags=Tag1,Tag2&dueDate=2025-11-30 +``` + +### Process to Obsidian + +``` +drafts://x-callback-url/runAction?action=Geoffrey%20Process%20Draft&uuid=UUID&destination=obsidian&folder=Meetings +``` + +### Archive + +``` +drafts://x-callback-url/runAction?action=Geoffrey%20Process%20Draft&uuid=UUID&destination=archive +``` + +### Trash + +``` +drafts://x-callback-url/runAction?action=Geoffrey%20Process%20Draft&uuid=UUID&destination=trash +``` diff --git a/skills/drafts-manager/actions/geoffrey-export-inbox.js b/skills/drafts-manager/actions/geoffrey-export-inbox.js new file mode 100644 index 0000000..9a1bd1f --- /dev/null +++ b/skills/drafts-manager/actions/geoffrey-export-inbox.js @@ -0,0 +1,53 @@ +// Geoffrey Export Inbox - Drafts Action +// Exports all inbox drafts to JSON file for Geoffrey to analyze +// +// To install: +// 1. Create new action in Drafts named "Geoffrey Export Inbox" +// 2. Add a "Script" step +// 3. Paste this code + +// Query inbox drafts (not archived, not trashed) +let drafts = Draft.query("", "inbox", [], [], "modified", true, false); + +// Build export data +let exportData = { + exported: new Date().toISOString(), + count: drafts.length, + drafts: [] +}; + +// Process each draft +drafts.forEach(d => { + exportData.drafts.push({ + uuid: d.uuid, + title: d.title || "(untitled)", + content: d.content, + tags: d.tags, + createdAt: d.createdAt.toISOString(), + modifiedAt: d.modifiedAt.toISOString(), + isFlagged: d.isFlagged, + wordCount: d.content.split(/\s+/).filter(w => w.length > 0).length + }); +}); + +// Write to iCloud Documents folder +let fm = FileManager.createCloud(); +let exportPath = "geoffrey-export.json"; +let jsonContent = JSON.stringify(exportData, null, 2); + +let success = fm.writeString(exportPath, jsonContent); + +if (success) { + // Show confirmation + app.displayInfoMessage("Exported " + drafts.length + " drafts for Geoffrey"); + + // Set draft content to summary (for callback if needed) + draft.content = JSON.stringify({ + status: "success", + count: drafts.length, + path: exportPath + }); +} else { + app.displayErrorMessage("Failed to write export file"); + context.fail("Export failed"); +} diff --git a/skills/drafts-manager/actions/geoffrey-process-draft.js b/skills/drafts-manager/actions/geoffrey-process-draft.js new file mode 100644 index 0000000..2ee7e96 --- /dev/null +++ b/skills/drafts-manager/actions/geoffrey-process-draft.js @@ -0,0 +1,185 @@ +// Geoffrey Process Draft - Drafts Action +// Processes a single draft based on routing instructions +// +// Call via URL with JSON in text parameter: +// drafts://x-callback-url/runAction?action=Geoffrey%20Process%20Draft&text={"uuid":"...","destination":"..."} +// +// JSON parameters: +// - uuid: Draft UUID to process +// - destination: "omnifocus", "obsidian", "archive", or "trash" +// - project: OmniFocus project name (for omnifocus destination) +// - tags: Comma-separated OmniFocus tags (for omnifocus destination) +// - dueDate: Due date string (for omnifocus destination) +// - folder: Obsidian folder path (for obsidian destination) +// +// To install: +// 1. Create new action in Drafts named "Geoffrey Process Draft" +// 2. Add a "Script" step +// 3. Paste this code + +// Parse parameters from draft content (passed as JSON via URL text parameter) +let params; +try { + params = JSON.parse(draft.content); +} catch (e) { + app.displayErrorMessage("Invalid JSON parameters: " + e.message); + context.fail("Invalid JSON"); +} + +let uuid = params.uuid; +let destination = params.destination; +let project = params.project || ""; +let tags = params.tags || ""; +let dueDate = params.dueDate || ""; +let folder = params.folder || "Geoffrey/Inbox"; + +// Validate required parameters +if (!uuid) { + app.displayErrorMessage("Missing uuid parameter"); + context.fail("Missing uuid"); +} + +if (!destination) { + app.displayErrorMessage("Missing destination parameter"); + context.fail("Missing destination"); +} + +// Find the draft to process +let targetDraft = Draft.find(uuid); + +if (!targetDraft) { + app.displayErrorMessage("Draft not found: " + uuid); + context.fail("Draft not found"); +} + +let title = targetDraft.title || "(untitled)"; +let content = targetDraft.content; +let result = { uuid: uuid, title: title, destination: destination }; + +// Route based on destination +switch (destination) { + case "omnifocus": + // Build OmniFocus URL + let ofUrl = "omnifocus:///add?"; + let params = []; + + // Task name is first line + params.push("name=" + encodeURIComponent(title)); + + // Note is rest of content + let noteLines = content.split("\n").slice(1).join("\n").trim(); + if (noteLines) { + params.push("note=" + encodeURIComponent(noteLines)); + } + + // Project + if (project) { + params.push("project=" + encodeURIComponent(project)); + } + + // Due date + if (dueDate) { + params.push("due=" + encodeURIComponent(dueDate)); + } + + // Open OmniFocus URL + let ofCallback = CallbackURL.create(); + ofCallback.baseURL = ofUrl + params.join("&"); + + let ofSuccess = ofCallback.open(); + + if (ofSuccess) { + result.status = "success"; + result.project = project; + result.tags = tags; + + // Tag the draft as processed + targetDraft.addTag("sent-to-omnifocus"); + targetDraft.isArchived = true; + targetDraft.update(); + + app.displayInfoMessage("Task sent to OmniFocus: " + title); + } else { + result.status = "failed"; + result.error = "Failed to open OmniFocus"; + app.displayErrorMessage("Failed to send to OmniFocus"); + } + break; + + case "obsidian": + // Build Obsidian file path + let obsidianVault = "/Users/hagelk/Library/Mobile Documents/iCloud~md~obsidian/Documents/Personal_Notes"; + let fileName = title.replace(/[\/\\:*?"<>|]/g, "-") + ".md"; + let filePath = folder + "/" + fileName; + + // Build frontmatter + let frontmatter = [ + "---", + "created: " + new Date().toISOString().split("T")[0], + "source: drafts", + "draft-uuid: " + uuid, + "tags: [from-drafts]", + "---", + "" + ].join("\n"); + + // Full content with frontmatter + let obsidianContent = frontmatter + content; + + // Use Obsidian URL scheme to create file + let obsCallback = CallbackURL.create(); + obsCallback.baseURL = "obsidian://new"; + obsCallback.addParameter("vault", "Personal_Notes"); + obsCallback.addParameter("file", folder + "/" + fileName.replace(".md", "")); + obsCallback.addParameter("content", obsidianContent); + obsCallback.addParameter("overwrite", "true"); + + let obsSuccess = obsCallback.open(); + + if (obsSuccess) { + result.status = "success"; + result.folder = folder; + result.file = fileName; + + // Tag the draft as processed + targetDraft.addTag("sent-to-obsidian"); + targetDraft.isArchived = true; + targetDraft.update(); + + app.displayInfoMessage("Note saved to Obsidian: " + fileName); + } else { + result.status = "failed"; + result.error = "Failed to create Obsidian note"; + app.displayErrorMessage("Failed to save to Obsidian"); + } + break; + + case "archive": + // Simply archive the draft + targetDraft.addTag("archived-by-geoffrey"); + targetDraft.isArchived = true; + targetDraft.update(); + + result.status = "success"; + app.displayInfoMessage("Archived: " + title); + break; + + case "trash": + // Move to trash + targetDraft.addTag("trashed-by-geoffrey"); + targetDraft.isTrashed = true; + targetDraft.update(); + + result.status = "success"; + app.displayInfoMessage("Trashed: " + title); + break; + + default: + result.status = "failed"; + result.error = "Unknown destination: " + destination; + app.displayErrorMessage("Unknown destination: " + destination); + context.fail("Unknown destination"); +} + +// Set draft content to result (for potential callback) +draft.content = JSON.stringify(result, null, 2); diff --git a/skills/drafts-manager/scripts/add_contact.js b/skills/drafts-manager/scripts/add_contact.js new file mode 100644 index 0000000..62a5e6b --- /dev/null +++ b/skills/drafts-manager/scripts/add_contact.js @@ -0,0 +1,94 @@ +#!/usr/bin/env osascript -l JavaScript +// Add contact to iCloud Contacts +// Usage: osascript -l JavaScript add_contact.js '{"name": "First Last", "phone": "123-456-7890", "email": "email@example.com", "organization": "Company"}' +// +// All fields except name are optional + +function run(argv) { + if (argv.length === 0) { + return JSON.stringify({ + error: "Missing parameters", + usage: 'osascript -l JavaScript add_contact.js \'{"name":"...", "phone":"...", "email":"..."}\'' + }); + } + + let params; + try { + params = JSON.parse(argv[0]); + } catch (e) { + return JSON.stringify({ + error: "Invalid JSON", + details: e.message + }); + } + + if (!params.name) { + return JSON.stringify({ error: "Missing name parameter" }); + } + + // Parse name into first/last + let nameParts = params.name.trim().split(/\s+/); + let firstName = nameParts[0] || ""; + let lastName = nameParts.slice(1).join(" ") || ""; + + const Contacts = Application("Contacts"); + + try { + // Create new person + let person = Contacts.Person({ + firstName: firstName, + lastName: lastName + }); + + // Add to contacts + Contacts.people.push(person); + + // Add phone if provided + if (params.phone) { + let phone = Contacts.Phone({ + label: "work", + value: params.phone.replace(/[^\d+()-\s]/g, "") + }); + person.phones.push(phone); + } + + // Add email if provided + if (params.email) { + let email = Contacts.Email({ + label: "work", + value: params.email + }); + person.emails.push(email); + } + + // Add organization if provided + if (params.organization) { + person.organization = params.organization; + } + + // Add note if provided + if (params.note) { + person.note = params.note; + } + + // Save + Contacts.save(); + + return JSON.stringify({ + success: true, + contact: { + firstName: firstName, + lastName: lastName, + phone: params.phone || null, + email: params.email || null, + organization: params.organization || null + } + }); + + } catch (e) { + return JSON.stringify({ + error: "Failed to create contact", + details: e.message + }); + } +} diff --git a/skills/drafts-manager/scripts/trigger_export.js b/skills/drafts-manager/scripts/trigger_export.js new file mode 100644 index 0000000..368b440 --- /dev/null +++ b/skills/drafts-manager/scripts/trigger_export.js @@ -0,0 +1,85 @@ +#!/usr/bin/env bun +// Trigger Geoffrey Export Inbox action in Drafts +// Usage: bun trigger_export.js +// +// This triggers the Drafts action and waits for the export file to be created. +// Returns the path to the export file. + +const { execSync } = require("child_process"); +const fs = require("fs"); +const path = require("path"); + +// Export file location +const exportPath = path.join( + process.env.HOME, + "Library/Mobile Documents/iCloud~com~agiletortoise~Drafts5/Documents/geoffrey-export.json" +); + +// Check if Drafts is running +try { + execSync('pgrep -x "Drafts"', { stdio: "pipe" }); +} catch (e) { + console.error(JSON.stringify({ + error: "Drafts is not running", + suggestion: "Please open Drafts and try again" + })); + process.exit(1); +} + +// Get current file modification time (if exists) +let oldMtime = 0; +try { + const stats = fs.statSync(exportPath); + oldMtime = stats.mtimeMs; +} catch (e) { + // File doesn't exist yet, that's fine +} + +// Trigger the export action +const actionUrl = "drafts://x-callback-url/runAction?action=" + + encodeURIComponent("Geoffrey Export Inbox"); + +try { + execSync(`open "${actionUrl}"`, { stdio: "pipe" }); +} catch (e) { + console.error(JSON.stringify({ + error: "Failed to trigger Drafts action", + details: e.message + })); + process.exit(1); +} + +// Wait for the export file to be updated (max 10 seconds) +const maxWait = 10000; +const checkInterval = 500; +let waited = 0; + +while (waited < maxWait) { + try { + const stats = fs.statSync(exportPath); + if (stats.mtimeMs > oldMtime) { + // File was updated, success! + const data = JSON.parse(fs.readFileSync(exportPath, "utf-8")); + console.log(JSON.stringify({ + status: "success", + path: exportPath, + count: data.count, + exported: data.exported + })); + process.exit(0); + } + } catch (e) { + // File doesn't exist yet, keep waiting + } + + // Sleep + execSync(`sleep ${checkInterval / 1000}`); + waited += checkInterval; +} + +// Timeout +console.error(JSON.stringify({ + error: "Timeout waiting for export file", + suggestion: "Check if the 'Geoffrey Export Inbox' action is installed in Drafts" +})); +process.exit(1); diff --git a/skills/drafts-manager/scripts/trigger_process.js b/skills/drafts-manager/scripts/trigger_process.js new file mode 100644 index 0000000..fbb5438 --- /dev/null +++ b/skills/drafts-manager/scripts/trigger_process.js @@ -0,0 +1,94 @@ +#!/usr/bin/env bun +// Trigger Geoffrey Process Draft action in Drafts +// Usage: bun trigger_process.js '' +// +// JSON params: +// { +// "uuid": "ABC123", +// "destination": "omnifocus|obsidian|archive|trash", +// "project": "Project Name", // for omnifocus +// "tags": "Tag1,Tag2", // for omnifocus +// "dueDate": "2025-11-30", // for omnifocus +// "folder": "Geoffrey/Inbox" // for obsidian +// } + +const { execSync } = require("child_process"); + +// Parse arguments +const args = process.argv.slice(2); +if (args.length === 0) { + console.error(JSON.stringify({ + error: "Missing parameters", + usage: 'bun trigger_process.js \'{"uuid":"...","destination":"..."}\'' + })); + process.exit(1); +} + +let params; +try { + params = JSON.parse(args[0]); +} catch (e) { + console.error(JSON.stringify({ + error: "Invalid JSON parameters", + details: e.message + })); + process.exit(1); +} + +// Validate required parameters +if (!params.uuid) { + console.error(JSON.stringify({ error: "Missing uuid parameter" })); + process.exit(1); +} + +if (!params.destination) { + console.error(JSON.stringify({ error: "Missing destination parameter" })); + process.exit(1); +} + +const validDestinations = ["omnifocus", "obsidian", "archive", "trash"]; +if (!validDestinations.includes(params.destination)) { + console.error(JSON.stringify({ + error: "Invalid destination", + valid: validDestinations + })); + process.exit(1); +} + +// Check if Drafts is running +try { + execSync('pgrep -x "Drafts"', { stdio: "pipe" }); +} catch (e) { + console.error(JSON.stringify({ + error: "Drafts is not running", + suggestion: "Please open Drafts and try again" + })); + process.exit(1); +} + +// Build URL with JSON in text parameter +const jsonPayload = JSON.stringify(params); +const actionUrl = "drafts://x-callback-url/runAction?action=" + + encodeURIComponent("Geoffrey Process Draft") + + "&text=" + encodeURIComponent(jsonPayload); + +// Trigger the action +try { + execSync(`open "${actionUrl}"`, { stdio: "pipe" }); + + // Give Drafts a moment to process + execSync("sleep 1"); + + console.log(JSON.stringify({ + status: "success", + uuid: params.uuid, + destination: params.destination, + details: params + })); +} catch (e) { + console.error(JSON.stringify({ + error: "Failed to trigger Drafts action", + details: e.message + })); + process.exit(1); +} diff --git a/skills/freshservice-manager/SKILL.md b/skills/freshservice-manager/SKILL.md new file mode 100644 index 0000000..34996a6 --- /dev/null +++ b/skills/freshservice-manager/SKILL.md @@ -0,0 +1,240 @@ +--- +name: freshservice-manager +description: Manage Freshservice tickets, approvals, and get team performance reports across all workspaces +triggers: + - "freshservice" + - "ticket" + - "helpdesk" + - "what happened in freshservice" + - "tech team metrics" + - "daily summary" + - "weekly summary" + - "approvals" + - "assign to" + - "add note to ticket" + - "close ticket" +allowed-tools: Read, Bash +version: 0.1.0 +--- + +# Freshservice Manager Skill + +## Configuration + +- **Domain**: psd401.freshservice.com +- **Agent ID**: 6000130414 (Kris Hagel) +- **Primary Workspace**: 2 (Technology) +- **API Key**: Stored in `~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env` + +## Workspaces + +| ID | Name | +|----|------| +| 2 | Technology (primary) | +| 3 | Employee Support Services | +| 4 | Business Services | +| 5 | Teaching & Learning | +| 6 | Maintenance | +| 8 | Investigations | +| 9 | Transportation | +| 10 | Safety & Security | +| 11 | Communications | +| 13 | Software Development | + +## Team Context + +- **TSD Generic Account** (6000875582) - Shared by high school interns for Chromebook repairs +- **David Edwards** - Desktop Support Tech, handles most varied workload including incidents +- **Carol Winget** - Student Database Admin, PowerSchool specialist +- **Laura Durkin** - Admin Secretary, handles new students and badges + +## Reports & Summaries + +### Daily Summary +Get a narrative summary of what happened in Technology on a specific day. + +**Natural language triggers:** +- "What happened in Freshservice yesterday?" +- "Give me today's tech summary" +- "What did the team do on Wednesday?" + +**Script:** `bun get_daily_summary.js [date]` + +Date options: +- `today` (default) +- `yesterday` +- Day names: `monday`, `tuesday`, `wednesday`, etc. +- `last wednesday`, `last friday` +- Specific date: `2025-11-20` + +**Output includes:** +- Total tickets closed +- Breakdown by category (Chromebook, Schoology, Security Alert, etc.) +- Breakdown by agent with their tickets +- Automated ticket count (password resets) + +### Weekly Summary +Get trends and metrics for the entire week. + +**Natural language triggers:** +- "Weekly tech summary" +- "How did the team do this week?" +- "Give me the weekly Freshservice report" + +**Script:** `bun get_weekly_summary.js [weeks_ago]` + +Options: +- `0` = this week (default) +- `1` = last week +- `2` = two weeks ago + +**Output includes:** +- Total closed and daily average +- Peak day and slow day +- Daily trend by volume +- Category breakdown with percentages +- Category trends (which days had spikes) +- Top agents with ticket counts and focus areas +- Agent daily breakdown + +### Narrative Style + +When presenting summaries, write a 1-minute narrative that: +- Highlights the main story of the day/week (outages, big pushes, etc.) +- Calls out specific people and what they handled +- Notes any concerning patterns (security alerts, cut wires, etc.) +- Converts UTC timestamps to Pacific time +- Uses specific numbers and ticket counts + +## Ticket Operations + +### List Tickets +```bash +bun list_tickets.js '{"workspace_id": 2, "filter": "new_and_my_open"}' +``` + +Filters: `new_and_my_open`, `watching`, `spam`, `deleted`, `archived` + +### Search Tickets +```bash +bun search_tickets.js "status:2 AND priority:3" 2 +``` + +Query syntax: `field:value AND/OR field:value` +Fields: `status`, `priority`, `agent_id`, `group_id`, `created_at`, `updated_at` + +### Get Ticket Details +```bash +bun get_ticket.js +``` + +### Get Service Request (with form data) +```bash +bun get_service_request.js +``` + +Includes requester info, custom form fields, requested items. + +### Create Ticket +```bash +bun create_ticket.js '' +``` + +Required: `subject`, `description`, `email` or `requester_id` +Optional: `priority`, `status`, `workspace_id` + +### Update Ticket +```bash +bun update_ticket.js '' +``` + +Can update: `status`, `priority`, `responder_id`, `group_id` + +### Add Note +```bash +bun add_note.js '{"body": "Note text", "private": true}' +``` + +Optional: `notify_emails` array to alert specific agents. + +## Agent Operations + +### List Agents +```bash +bun list_agents.js [query] +``` + +Query filters by first name, last name, or email. +Returns: id, name, email, job_title + +Use this to resolve "assign to Mark" → find Mark's agent ID → update ticket. + +### Get Agent by Email +```bash +bun get_agent.js +``` + +## Approvals + +### Get Pending Approvals +```bash +bun get_approvals.js [status] +``` + +Status: `requested` (default), `approved`, `rejected`, `cancelled` + +**Note:** Freshservice API does not support approving service requests programmatically. User must approve via: +- Web UI: `https://psd401.freshservice.com/helpdesk/tickets/` +- Email reply to approval request + +## Common Workflows + +### "Add a note to Jodi on ticket 151501" +1. Find Jodi's agent ID: `bun list_agents.js jodi` → 6000542935 +2. Add note: `bun add_note.js 151501 '{"body": "...", "notify_emails": ["miloj@psd401.net"]}'` + +### "Assign ticket to Mark" +1. Find Mark's ID: `bun list_agents.js mark` +2. Update ticket: `bun update_ticket.js '{"responder_id": }'` + +### "What approvals do I have?" +1. Get approvals: `bun get_approvals.js` +2. For each approval, get details: `bun get_service_request.js ` + +### Cross-skill workflow +"Add note to ticket, create OmniFocus task, reassign ticket" - can combine Freshservice note + OmniFocus task creation + ticket update in one flow. + +## Category Detection + +Tickets are auto-categorized by subject keywords: +- **Password Reset**: "password reset" +- **Security Alert**: "security alert", "compromised", "breach" +- **Schoology**: "schoology" +- **PowerSchool**: "powerschool" +- **Promethean Board**: "promethean" +- **Chromebook**: "chromebook" +- **Phone/Voicemail**: "phone", "voicemail", "ext." +- **Badge Request**: "badge" +- **New Student**: "new student", "enrollee" +- **Intercom**: "intercom" +- **Raptor**: "raptor" +- **GoGuardian**: "goguardian", "go guardian" +- **Access/Login**: "login", "access", "mfa" + +## Status Codes + +| Code | Status | +|------|--------| +| 2 | Open | +| 3 | Pending | +| 4 | Resolved | +| 5 | Closed | + +## Priority Codes + +| Code | Priority | +|------|----------| +| 1 | Low | +| 2 | Medium | +| 3 | High | +| 4 | Urgent | diff --git a/skills/freshservice-manager/scripts/add_note.js b/skills/freshservice-manager/scripts/add_note.js new file mode 100644 index 0000000..9a3ed1f --- /dev/null +++ b/skills/freshservice-manager/scripts/add_note.js @@ -0,0 +1,81 @@ +#!/usr/bin/env bun + +// Add a note to a ticket +// Usage: bun add_note.js '' +// JSON: {"body": "Note text", "private": true, "notify_emails": ["email@example.com"]} + +import { readFileSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; + +function loadEnv() { + const envPath = join(homedir(), 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env'); + const content = readFileSync(envPath, 'utf-8'); + const env = {}; + for (const line of content.split('\n')) { + if (line && !line.startsWith('#')) { + const [key, ...valueParts] = line.split('='); + if (key && valueParts.length) { + env[key.trim()] = valueParts.join('=').trim(); + } + } + } + return env; +} + +const env = loadEnv(); +const domain = env.FRESHSERVICE_DOMAIN; +const apiKey = env.FRESHSERVICE_API_KEY; +const baseUrl = `https://${domain}/api/v2`; + +const ticketId = process.argv[2]; +let noteData; + +if (!ticketId) { + console.error(JSON.stringify({ error: 'Ticket ID required' })); + process.exit(1); +} + +try { + noteData = JSON.parse(process.argv[3]); +} catch (e) { + console.error(JSON.stringify({ error: 'Invalid JSON. Required: {"body": "note text"}' })); + process.exit(1); +} + +if (!noteData.body) { + console.error(JSON.stringify({ error: 'Note body is required' })); + process.exit(1); +} + +// Default to private note +if (noteData.private === undefined) { + noteData.private = true; +} + +async function addNote(ticketId, data) { + const response = await fetch(`${baseUrl}/tickets/${ticketId}/notes`, { + method: 'POST', + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }); + + if (!response.ok) { + const error = await response.text(); + return { error: `API error ${response.status}: ${error}` }; + } + + const result = await response.json(); + return result; +} + +try { + const result = await addNote(ticketId, noteData); + console.log(JSON.stringify(result, null, 2)); +} catch (e) { + console.error(JSON.stringify({ error: e.message })); + process.exit(1); +} diff --git a/skills/freshservice-manager/scripts/create_ticket.js b/skills/freshservice-manager/scripts/create_ticket.js new file mode 100644 index 0000000..441d52b --- /dev/null +++ b/skills/freshservice-manager/scripts/create_ticket.js @@ -0,0 +1,76 @@ +#!/usr/bin/env bun + +// Create a new ticket +// Usage: bun create_ticket.js '' +// JSON: {"subject": "...", "description": "...", "email": "requester@email.com", "priority": 2, "status": 2, "workspace_id": 2} + +import { readFileSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; + +function loadEnv() { + const envPath = join(homedir(), 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env'); + const content = readFileSync(envPath, 'utf-8'); + const env = {}; + for (const line of content.split('\n')) { + if (line && !line.startsWith('#')) { + const [key, ...valueParts] = line.split('='); + if (key && valueParts.length) { + env[key.trim()] = valueParts.join('=').trim(); + } + } + } + return env; +} + +const env = loadEnv(); +const domain = env.FRESHSERVICE_DOMAIN; +const apiKey = env.FRESHSERVICE_API_KEY; +const baseUrl = `https://${domain}/api/v2`; + +// Status values: 2=Open, 3=Pending, 4=Resolved, 5=Closed +// Priority values: 1=Low, 2=Medium, 3=High, 4=Urgent + +let ticketData; +try { + ticketData = JSON.parse(process.argv[2]); +} catch (e) { + console.error(JSON.stringify({ error: 'Invalid JSON. Required: subject, description, email' })); + process.exit(1); +} + +if (!ticketData.subject || !ticketData.description || !ticketData.email) { + console.error(JSON.stringify({ error: 'Required fields: subject, description, email' })); + process.exit(1); +} + +// Set defaults +ticketData.status = ticketData.status || 2; // Open +ticketData.priority = ticketData.priority || 2; // Medium + +async function createTicket(data) { + const response = await fetch(`${baseUrl}/tickets`, { + method: 'POST', + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }); + + if (!response.ok) { + const error = await response.text(); + return { error: `API error ${response.status}: ${error}` }; + } + + const result = await response.json(); + return result; +} + +try { + const result = await createTicket(ticketData); + console.log(JSON.stringify(result, null, 2)); +} catch (e) { + console.error(JSON.stringify({ error: e.message })); + process.exit(1); +} diff --git a/skills/freshservice-manager/scripts/get_agent.js b/skills/freshservice-manager/scripts/get_agent.js new file mode 100644 index 0000000..cb3ca4a --- /dev/null +++ b/skills/freshservice-manager/scripts/get_agent.js @@ -0,0 +1,67 @@ +#!/usr/bin/env bun + +// Get agent info by email +// Usage: bun get_agent.js [email] +// If no email provided, returns current agent (API key owner) + +import { readFileSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; + +// Load environment from iCloud secrets +function loadEnv() { + const envPath = join(homedir(), 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env'); + const content = readFileSync(envPath, 'utf-8'); + const env = {}; + for (const line of content.split('\n')) { + if (line && !line.startsWith('#')) { + const [key, ...valueParts] = line.split('='); + if (key && valueParts.length) { + env[key.trim()] = valueParts.join('=').trim(); + } + } + } + return env; +} + +const env = loadEnv(); +const domain = env.FRESHSERVICE_DOMAIN; +const apiKey = env.FRESHSERVICE_API_KEY; + +if (!domain || !apiKey) { + console.error(JSON.stringify({ error: 'Missing FRESHSERVICE_DOMAIN or FRESHSERVICE_API_KEY in .env' })); + process.exit(1); +} + +const email = process.argv[2]; +const baseUrl = `https://${domain}/api/v2`; + +async function getAgents(email) { + let url = `${baseUrl}/agents`; + if (email) { + url += `?email=${encodeURIComponent(email)}`; + } + + const response = await fetch(url, { + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + const error = await response.text(); + return { error: `API error ${response.status}: ${error}` }; + } + + const data = await response.json(); + return data; +} + +try { + const result = await getAgents(email); + console.log(JSON.stringify(result, null, 2)); +} catch (e) { + console.error(JSON.stringify({ error: e.message })); + process.exit(1); +} diff --git a/skills/freshservice-manager/scripts/get_approvals.js b/skills/freshservice-manager/scripts/get_approvals.js new file mode 100644 index 0000000..2875518 --- /dev/null +++ b/skills/freshservice-manager/scripts/get_approvals.js @@ -0,0 +1,94 @@ +#!/usr/bin/env bun + +// Get approvals for the current agent +// Usage: bun get_approvals.js [status] +// Status: requested (pending), approved, rejected, cancelled + +import { readFileSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; + +function loadEnv() { + const envPath = join(homedir(), 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env'); + const content = readFileSync(envPath, 'utf-8'); + const env = {}; + for (const line of content.split('\n')) { + if (line && !line.startsWith('#')) { + const [key, ...valueParts] = line.split('='); + if (key && valueParts.length) { + env[key.trim()] = valueParts.join('=').trim(); + } + } + } + return env; +} + +const env = loadEnv(); +const domain = env.FRESHSERVICE_DOMAIN; +const apiKey = env.FRESHSERVICE_API_KEY; +const baseUrl = `https://${domain}/api/v2`; + +// Agent ID for Kris Hagel +const agentId = 6000130414; +const status = process.argv[2] || 'requested'; + +async function getApprovals(agentId, status, parent) { + const url = `${baseUrl}/approvals?approver_id=${agentId}&status=${status}&parent=${parent}`; + + const response = await fetch(url, { + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + const error = await response.text(); + return { error: `API error ${response.status}: ${error}` }; + } + + const data = await response.json(); + + // Simplify output + const approvals = data.approvals.map(a => ({ + id: a.id, + approval_type: a.approval_type, + approver_id: a.approver_id, + status: a.status, + created_at: a.created_at, + updated_at: a.updated_at, + approvable_id: a.approvable_id, + approvable_type: a.approvable_type, + delegator: a.delegator, + latest_remark: a.latest_remark + })); + + return { + count: approvals.length, + status: status, + approvals + }; +} + +try { + // Check both tickets and changes for approvals + const ticketApprovals = await getApprovals(agentId, status, 'ticket'); + const changeApprovals = await getApprovals(agentId, status, 'change'); + + const allApprovals = []; + if (!ticketApprovals.error) { + allApprovals.push(...ticketApprovals.approvals.map(a => ({...a, parent_type: 'ticket'}))); + } + if (!changeApprovals.error) { + allApprovals.push(...changeApprovals.approvals.map(a => ({...a, parent_type: 'change'}))); + } + + console.log(JSON.stringify({ + count: allApprovals.length, + status: status, + approvals: allApprovals + }, null, 2)); +} catch (e) { + console.error(JSON.stringify({ error: e.message })); + process.exit(1); +} diff --git a/skills/freshservice-manager/scripts/get_daily_summary.js b/skills/freshservice-manager/scripts/get_daily_summary.js new file mode 100644 index 0000000..41eaf8e --- /dev/null +++ b/skills/freshservice-manager/scripts/get_daily_summary.js @@ -0,0 +1,285 @@ +#!/usr/bin/env bun + +// Get daily ticket summary for Technology workspace +// Usage: bun get_daily_summary.js [date] +// Date: "yesterday", "today", or specific date like "2025-11-20" + +import { readFileSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; + +function loadEnv() { + const envPath = join(homedir(), 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env'); + const content = readFileSync(envPath, 'utf-8'); + const env = {}; + for (const line of content.split('\n')) { + if (line && !line.startsWith('#')) { + const [key, ...valueParts] = line.split('='); + if (key && valueParts.length) { + env[key.trim()] = valueParts.join('=').trim(); + } + } + } + return env; +} + +const env = loadEnv(); +const domain = env.FRESHSERVICE_DOMAIN; +const apiKey = env.FRESHSERVICE_API_KEY; +const baseUrl = `https://${domain}/api/v2`; + +// Parse date argument +function parseDate(dateArg) { + const now = new Date(); + + if (!dateArg || dateArg === 'today') { + return { + start: new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0), + end: new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59), + label: 'today' + }; + } + + if (dateArg === 'yesterday') { + const yesterday = new Date(now); + yesterday.setDate(yesterday.getDate() - 1); + return { + start: new Date(yesterday.getFullYear(), yesterday.getMonth(), yesterday.getDate(), 0, 0, 0), + end: new Date(yesterday.getFullYear(), yesterday.getMonth(), yesterday.getDate(), 23, 59, 59), + label: 'yesterday' + }; + } + + // Handle "last " format (e.g., "last wednesday", "last friday") + const dayNames = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']; + const lower = dateArg.toLowerCase(); + + if (lower.startsWith('last ')) { + const dayName = lower.replace('last ', '').trim(); + const targetDay = dayNames.indexOf(dayName); + + if (targetDay !== -1) { + const currentDay = now.getDay(); + let daysBack = currentDay - targetDay; + if (daysBack <= 0) daysBack += 7; // Go to previous week + + const targetDate = new Date(now); + targetDate.setDate(targetDate.getDate() - daysBack); + + return { + start: new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate(), 0, 0, 0), + end: new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate(), 23, 59, 59), + label: `last ${dayName.charAt(0).toUpperCase() + dayName.slice(1)}` + }; + } + } + + // Handle just day name (e.g., "wednesday" means this past wednesday) + const justDay = dayNames.indexOf(lower); + if (justDay !== -1) { + const currentDay = now.getDay(); + let daysBack = currentDay - justDay; + if (daysBack < 0) daysBack += 7; + if (daysBack === 0) daysBack = 7; // If today is that day, go back a week + + const targetDate = new Date(now); + targetDate.setDate(targetDate.getDate() - daysBack); + + return { + start: new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate(), 0, 0, 0), + end: new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate(), 23, 59, 59), + label: targetDate.toLocaleDateString('en-US', { weekday: 'long', month: 'short', day: 'numeric' }) + }; + } + + // Parse specific date + const date = new Date(dateArg); + return { + start: new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0), + end: new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59), + label: date.toLocaleDateString('en-US', { weekday: 'long', month: 'short', day: 'numeric' }) + }; +} + +// Convert Pacific time to UTC for API query +function toUTC(date) { + // Pacific is UTC-8 (or UTC-7 during DST) + // Add 8 hours to convert Pacific to UTC + const utc = new Date(date.getTime() + (8 * 60 * 60 * 1000)); + return utc.toISOString(); +} + +// Get all agents for name mapping +async function getAgents() { + const response = await fetch(`${baseUrl}/agents?per_page=100`, { + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) return {}; + + const data = await response.json(); + const agentMap = {}; + for (const agent of data.agents) { + agentMap[agent.id] = { + name: `${agent.first_name} ${agent.last_name}`, + first_name: agent.first_name, + job_title: agent.job_title + }; + } + return agentMap; +} + +// Search tickets closed on date (with pagination) +async function searchTickets(startDate, endDate, workspaceId = 2) { + const startUTC = toUTC(startDate); + const endUTC = toUTC(endDate); + + const query = `(status:4 OR status:5) AND updated_at:>'${startUTC.split('T')[0]}T00:00:00Z' AND updated_at:<'${endUTC.split('T')[0]}T23:59:59Z'`; + + let allTickets = []; + let page = 1; + let hasMore = true; + + while (hasMore) { + const url = `${baseUrl}/tickets/filter?query="${encodeURIComponent(query)}"&workspace_id=${workspaceId}&page=${page}&per_page=100`; + + const response = await fetch(url, { + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + const error = await response.text(); + return { error: `API error ${response.status}: ${error}` }; + } + + const data = await response.json(); + allTickets = allTickets.concat(data.tickets || []); + + // Check if there are more pages + hasMore = (data.tickets || []).length === 100; + page++; + } + + return { tickets: allTickets }; +} + +// Categorize ticket by subject +function categorizeTicket(subject) { + const lower = subject.toLowerCase(); + + if (lower.includes('password reset')) return 'Password Reset'; + if (lower.includes('security alert') || lower.includes('compromised') || lower.includes('breach')) return 'Security Alert'; + if (lower.includes('schoology')) return 'Schoology'; + if (lower.includes('powerschool')) return 'PowerSchool'; + if (lower.includes('promethean')) return 'Promethean Board'; + if (lower.includes('chromebook')) return 'Chromebook'; + if (lower.includes('phone') || lower.includes('voicemail') || lower.includes('ext.')) return 'Phone/Voicemail'; + if (lower.includes('badge')) return 'Badge Request'; + if (lower.includes('new student') || lower.includes('enrollee')) return 'New Student'; + if (lower.includes('intercom')) return 'Intercom'; + if (lower.includes('raptor')) return 'Raptor'; + if (lower.includes('goguardian') || lower.includes('go guardian')) return 'GoGuardian'; + if (lower.includes('login') || lower.includes('access') || lower.includes('mfa')) return 'Access/Login'; + + return 'Other'; +} + +const dateArg = process.argv[2]; +const dateRange = parseDate(dateArg); + +try { + const [ticketData, agentMap] = await Promise.all([ + searchTickets(dateRange.start, dateRange.end), + getAgents() + ]); + + if (ticketData.error) { + console.error(JSON.stringify(ticketData)); + process.exit(1); + } + + const tickets = ticketData.tickets || []; + + // Group by agent + const byAgent = {}; + const byCategory = {}; + const automated = []; + + for (const ticket of tickets) { + const category = categorizeTicket(ticket.subject); + byCategory[category] = (byCategory[category] || 0) + 1; + + if (!ticket.responder_id) { + automated.push({ + id: ticket.id, + subject: ticket.subject, + category, + updated_at: ticket.updated_at + }); + continue; + } + + const agentId = ticket.responder_id; + if (!byAgent[agentId]) { + byAgent[agentId] = { + agent: agentMap[agentId] || { name: `Agent ${agentId}`, first_name: 'Unknown' }, + tickets: [], + categories: {} + }; + } + + byAgent[agentId].tickets.push({ + id: ticket.id, + subject: ticket.subject, + category, + status: ticket.status, + priority: ticket.priority, + created_at: ticket.created_at, + updated_at: ticket.updated_at + }); + + byAgent[agentId].categories[category] = (byAgent[agentId].categories[category] || 0) + 1; + } + + // Sort agents by ticket count + const sortedAgents = Object.entries(byAgent) + .map(([id, data]) => ({ + id, + name: data.agent.name, + first_name: data.agent.first_name, + job_title: data.agent.job_title, + count: data.tickets.length, + categories: data.categories, + tickets: data.tickets.sort((a, b) => new Date(a.updated_at) - new Date(b.updated_at)) + })) + .sort((a, b) => b.count - a.count); + + // Build summary + const summary = { + date: dateRange.label, + date_range: { + start: dateRange.start.toISOString(), + end: dateRange.end.toISOString() + }, + total_closed: tickets.length, + by_category: Object.entries(byCategory) + .sort((a, b) => b[1] - a[1]) + .reduce((acc, [k, v]) => { acc[k] = v; return acc; }, {}), + by_agent: sortedAgents, + automated: { + count: automated.length, + tickets: automated + } + }; + + console.log(JSON.stringify(summary, null, 2)); +} catch (e) { + console.error(JSON.stringify({ error: e.message })); + process.exit(1); +} diff --git a/skills/freshservice-manager/scripts/get_service_request.js b/skills/freshservice-manager/scripts/get_service_request.js new file mode 100644 index 0000000..ded6a85 --- /dev/null +++ b/skills/freshservice-manager/scripts/get_service_request.js @@ -0,0 +1,139 @@ +#!/usr/bin/env bun + +// Get service request details including form data +// Usage: bun get_service_request.js + +import { readFileSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; + +function loadEnv() { + const envPath = join(homedir(), 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env'); + const content = readFileSync(envPath, 'utf-8'); + const env = {}; + for (const line of content.split('\n')) { + if (line && !line.startsWith('#')) { + const [key, ...valueParts] = line.split('='); + if (key && valueParts.length) { + env[key.trim()] = valueParts.join('=').trim(); + } + } + } + return env; +} + +const env = loadEnv(); +const domain = env.FRESHSERVICE_DOMAIN; +const apiKey = env.FRESHSERVICE_API_KEY; +const baseUrl = `https://${domain}/api/v2`; + +const ticketId = process.argv[2]; + +if (!ticketId) { + console.error(JSON.stringify({ error: 'Ticket ID required' })); + process.exit(1); +} + +async function getTicket(id) { + const response = await fetch(`${baseUrl}/tickets/${id}?include=conversations,requester`, { + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + const error = await response.text(); + return { error: `API error ${response.status}: ${error}` }; + } + + return await response.json(); +} + +async function getRequestedItems(ticketId) { + const response = await fetch(`${baseUrl}/tickets/${ticketId}/requested_items`, { + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + return { requested_items: [] }; + } + + return await response.json(); +} + +async function getRequester(requesterId) { + const response = await fetch(`${baseUrl}/requesters/${requesterId}`, { + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + return null; + } + + const data = await response.json(); + return data.requester; +} + +try { + const ticketData = await getTicket(ticketId); + if (ticketData.error) { + console.error(JSON.stringify(ticketData)); + process.exit(1); + } + + const ticket = ticketData.ticket; + const itemsData = await getRequestedItems(ticketId); + const requester = await getRequester(ticket.requester_id); + + // Build comprehensive response + const result = { + ticket: { + id: ticket.id, + subject: ticket.subject, + type: ticket.type, + status: ticket.status, + priority: ticket.priority, + category: ticket.category, + sub_category: ticket.sub_category, + item_category: ticket.item_category, + workspace_id: ticket.workspace_id, + created_at: ticket.created_at, + due_by: ticket.due_by, + is_escalated: ticket.is_escalated, + approval_status: ticket.approval_status, + approval_status_name: ticket.approval_status_name + }, + requester: requester ? { + name: `${requester.first_name} ${requester.last_name}`, + email: requester.primary_email, + department: requester.department_names?.[0] || null, + job_title: requester.job_title + } : null, + form_data: itemsData.requested_items?.[0]?.custom_fields || {}, + service_item: itemsData.requested_items?.[0] ? { + id: itemsData.requested_items[0].service_item_id, + name: itemsData.requested_items[0].service_item_name, + quantity: itemsData.requested_items[0].quantity, + cost: itemsData.requested_items[0].cost_per_request + } : null, + conversations: ticket.conversations?.map(c => ({ + id: c.id, + body_text: c.body_text, + private: c.private, + created_at: c.created_at, + user_id: c.user_id + })) || [] + }; + + console.log(JSON.stringify(result, null, 2)); +} catch (e) { + console.error(JSON.stringify({ error: e.message })); + process.exit(1); +} diff --git a/skills/freshservice-manager/scripts/get_ticket.js b/skills/freshservice-manager/scripts/get_ticket.js new file mode 100644 index 0000000..f14e2f7 --- /dev/null +++ b/skills/freshservice-manager/scripts/get_ticket.js @@ -0,0 +1,67 @@ +#!/usr/bin/env bun + +// Get ticket details by ID +// Usage: bun get_ticket.js [include] +// Include options: conversations, requester, problem, stats, assets, change, related_tickets + +import { readFileSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; + +function loadEnv() { + const envPath = join(homedir(), 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env'); + const content = readFileSync(envPath, 'utf-8'); + const env = {}; + for (const line of content.split('\n')) { + if (line && !line.startsWith('#')) { + const [key, ...valueParts] = line.split('='); + if (key && valueParts.length) { + env[key.trim()] = valueParts.join('=').trim(); + } + } + } + return env; +} + +const env = loadEnv(); +const domain = env.FRESHSERVICE_DOMAIN; +const apiKey = env.FRESHSERVICE_API_KEY; +const baseUrl = `https://${domain}/api/v2`; + +const ticketId = process.argv[2]; +const include = process.argv[3]; + +if (!ticketId) { + console.error(JSON.stringify({ error: 'Ticket ID required' })); + process.exit(1); +} + +async function getTicket(id, include) { + let url = `${baseUrl}/tickets/${id}`; + if (include) { + url += `?include=${include}`; + } + + const response = await fetch(url, { + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + const error = await response.text(); + return { error: `API error ${response.status}: ${error}` }; + } + + const data = await response.json(); + return data; +} + +try { + const result = await getTicket(ticketId, include); + console.log(JSON.stringify(result, null, 2)); +} catch (e) { + console.error(JSON.stringify({ error: e.message })); + process.exit(1); +} diff --git a/skills/freshservice-manager/scripts/get_weekly_summary.js b/skills/freshservice-manager/scripts/get_weekly_summary.js new file mode 100644 index 0000000..2f629f3 --- /dev/null +++ b/skills/freshservice-manager/scripts/get_weekly_summary.js @@ -0,0 +1,280 @@ +#!/usr/bin/env bun + +// Get weekly ticket summary for Technology workspace with trends +// Usage: bun get_weekly_summary.js [weeks_ago] +// weeks_ago: 0 = this week (default), 1 = last week, etc. + +import { readFileSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; + +function loadEnv() { + const envPath = join(homedir(), 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env'); + const content = readFileSync(envPath, 'utf-8'); + const env = {}; + for (const line of content.split('\n')) { + if (line && !line.startsWith('#')) { + const [key, ...valueParts] = line.split('='); + if (key && valueParts.length) { + env[key.trim()] = valueParts.join('=').trim(); + } + } + } + return env; +} + +const env = loadEnv(); +const domain = env.FRESHSERVICE_DOMAIN; +const apiKey = env.FRESHSERVICE_API_KEY; +const baseUrl = `https://${domain}/api/v2`; + +// Get week date range (Monday to Sunday) +function getWeekRange(weeksAgo = 0) { + const now = new Date(); + const currentDay = now.getDay(); + const mondayOffset = currentDay === 0 ? -6 : 1 - currentDay; + + const monday = new Date(now); + monday.setDate(monday.getDate() + mondayOffset - (weeksAgo * 7)); + monday.setHours(0, 0, 0, 0); + + const sunday = new Date(monday); + sunday.setDate(sunday.getDate() + 6); + sunday.setHours(23, 59, 59, 999); + + const weekNum = getWeekNumber(monday); + + return { + start: monday, + end: sunday, + label: `Week ${weekNum} (${monday.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} - ${sunday.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })})` + }; +} + +function getWeekNumber(date) { + const firstDayOfYear = new Date(date.getFullYear(), 0, 1); + const pastDaysOfYear = (date - firstDayOfYear) / 86400000; + return Math.ceil((pastDaysOfYear + firstDayOfYear.getDay() + 1) / 7); +} + +// Convert Pacific time to UTC +function toUTC(date) { + const utc = new Date(date.getTime() + (8 * 60 * 60 * 1000)); + return utc.toISOString(); +} + +// Get all agents +async function getAgents() { + let allAgents = []; + let page = 1; + let hasMore = true; + + while (hasMore) { + const response = await fetch(`${baseUrl}/agents?per_page=100&page=${page}`, { + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) break; + + const data = await response.json(); + allAgents = allAgents.concat(data.agents); + hasMore = data.agents.length === 100; + page++; + } + + const agentMap = {}; + for (const agent of allAgents) { + agentMap[agent.id] = { + name: `${agent.first_name} ${agent.last_name}`, + first_name: agent.first_name, + job_title: agent.job_title + }; + } + return agentMap; +} + +// Search tickets with pagination +async function searchTickets(startDate, endDate, workspaceId = 2) { + const startUTC = toUTC(startDate); + const endUTC = toUTC(endDate); + + const query = `(status:4 OR status:5) AND updated_at:>'${startUTC.split('T')[0]}T00:00:00Z' AND updated_at:<'${endUTC.split('T')[0]}T23:59:59Z'`; + + let allTickets = []; + let page = 1; + let hasMore = true; + + while (hasMore) { + const url = `${baseUrl}/tickets/filter?query="${encodeURIComponent(query)}"&workspace_id=${workspaceId}&page=${page}&per_page=100`; + + const response = await fetch(url, { + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + const error = await response.text(); + return { error: `API error ${response.status}: ${error}` }; + } + + const data = await response.json(); + allTickets = allTickets.concat(data.tickets || []); + hasMore = (data.tickets || []).length === 100; + page++; + } + + return { tickets: allTickets }; +} + +// Categorize ticket +function categorizeTicket(subject) { + const lower = subject.toLowerCase(); + + if (lower.includes('password reset')) return 'Password Reset'; + if (lower.includes('security alert') || lower.includes('compromised') || lower.includes('breach')) return 'Security Alert'; + if (lower.includes('schoology')) return 'Schoology'; + if (lower.includes('powerschool')) return 'PowerSchool'; + if (lower.includes('promethean')) return 'Promethean Board'; + if (lower.includes('chromebook')) return 'Chromebook'; + if (lower.includes('phone') || lower.includes('voicemail') || lower.includes('ext.')) return 'Phone/Voicemail'; + if (lower.includes('badge')) return 'Badge Request'; + if (lower.includes('new student') || lower.includes('enrollee')) return 'New Student'; + if (lower.includes('intercom')) return 'Intercom'; + if (lower.includes('raptor')) return 'Raptor'; + if (lower.includes('goguardian') || lower.includes('go guardian')) return 'GoGuardian'; + if (lower.includes('login') || lower.includes('access') || lower.includes('mfa')) return 'Access/Login'; + + return 'Other'; +} + +// Get day name from date +function getDayName(date) { + return date.toLocaleDateString('en-US', { weekday: 'short' }); +} + +const weeksAgo = parseInt(process.argv[2] || '0'); +const weekRange = getWeekRange(weeksAgo); + +try { + const [ticketData, agentMap] = await Promise.all([ + searchTickets(weekRange.start, weekRange.end), + getAgents() + ]); + + if (ticketData.error) { + console.error(JSON.stringify(ticketData)); + process.exit(1); + } + + const tickets = ticketData.tickets || []; + + // Group by day + const byDay = {}; + const dayNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; + for (const day of dayNames) { + byDay[day] = { count: 0, categories: {}, agents: {} }; + } + + // Group by agent and category + const byAgent = {}; + const byCategory = {}; + const byCategoryByDay = {}; + + for (const ticket of tickets) { + // Determine day (convert UTC to Pacific) + const updatedAt = new Date(ticket.updated_at); + const pacificTime = new Date(updatedAt.getTime() - (8 * 60 * 60 * 1000)); + const dayName = getDayName(pacificTime); + + const category = categorizeTicket(ticket.subject); + + // By day + if (byDay[dayName]) { + byDay[dayName].count++; + byDay[dayName].categories[category] = (byDay[dayName].categories[category] || 0) + 1; + + if (ticket.responder_id) { + byDay[dayName].agents[ticket.responder_id] = (byDay[dayName].agents[ticket.responder_id] || 0) + 1; + } + } + + // By category + byCategory[category] = (byCategory[category] || 0) + 1; + + // By category by day + if (!byCategoryByDay[category]) { + byCategoryByDay[category] = {}; + } + byCategoryByDay[category][dayName] = (byCategoryByDay[category][dayName] || 0) + 1; + + // By agent + if (ticket.responder_id) { + if (!byAgent[ticket.responder_id]) { + byAgent[ticket.responder_id] = { + agent: agentMap[ticket.responder_id] || { name: `Agent ${ticket.responder_id}`, first_name: 'Unknown' }, + count: 0, + categories: {}, + byDay: {} + }; + } + byAgent[ticket.responder_id].count++; + byAgent[ticket.responder_id].categories[category] = (byAgent[ticket.responder_id].categories[category] || 0) + 1; + byAgent[ticket.responder_id].byDay[dayName] = (byAgent[ticket.responder_id].byDay[dayName] || 0) + 1; + } + } + + // Sort agents by count + const sortedAgents = Object.entries(byAgent) + .map(([id, data]) => ({ + id, + name: data.agent.name, + first_name: data.agent.first_name, + job_title: data.agent.job_title, + count: data.count, + categories: data.categories, + byDay: data.byDay, + avg_per_day: (data.count / 5).toFixed(1) // Assuming 5 work days + })) + .sort((a, b) => b.count - a.count); + + // Calculate trends + const dailyCounts = dayNames.slice(0, 5).map(d => byDay[d].count); // Mon-Fri + const avgDaily = dailyCounts.reduce((a, b) => a + b, 0) / 5; + const peakDay = dayNames.slice(0, 5).reduce((max, day) => byDay[day].count > byDay[max].count ? day : max, 'Mon'); + const slowDay = dayNames.slice(0, 5).reduce((min, day) => byDay[day].count < byDay[min].count ? day : min, 'Mon'); + + // Build summary + const summary = { + week: weekRange.label, + date_range: { + start: weekRange.start.toISOString(), + end: weekRange.end.toISOString() + }, + total_closed: tickets.length, + daily_average: avgDaily.toFixed(1), + trends: { + peak_day: { day: peakDay, count: byDay[peakDay].count }, + slow_day: { day: slowDay, count: byDay[slowDay].count }, + daily_counts: byDay + }, + by_category: Object.entries(byCategory) + .sort((a, b) => b[1] - a[1]) + .reduce((acc, [k, v]) => { + acc[k] = { total: v, pct: ((v / tickets.length) * 100).toFixed(1) + '%' }; + return acc; + }, {}), + category_trends: byCategoryByDay, + top_agents: sortedAgents.slice(0, 10), + all_agents: sortedAgents + }; + + console.log(JSON.stringify(summary, null, 2)); +} catch (e) { + console.error(JSON.stringify({ error: e.message })); + process.exit(1); +} diff --git a/skills/freshservice-manager/scripts/get_workspaces.js b/skills/freshservice-manager/scripts/get_workspaces.js new file mode 100644 index 0000000..8ac922c --- /dev/null +++ b/skills/freshservice-manager/scripts/get_workspaces.js @@ -0,0 +1,70 @@ +#!/usr/bin/env bun + +// Get workspace details +// Usage: bun get_workspaces.js [workspace_id] +// If no ID provided, gets all workspaces the agent has access to + +import { readFileSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; + +function loadEnv() { + const envPath = join(homedir(), 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env'); + const content = readFileSync(envPath, 'utf-8'); + const env = {}; + for (const line of content.split('\n')) { + if (line && !line.startsWith('#')) { + const [key, ...valueParts] = line.split('='); + if (key && valueParts.length) { + env[key.trim()] = valueParts.join('=').trim(); + } + } + } + return env; +} + +const env = loadEnv(); +const domain = env.FRESHSERVICE_DOMAIN; +const apiKey = env.FRESHSERVICE_API_KEY; +const baseUrl = `https://${domain}/api/v2`; + +async function getWorkspace(id) { + const response = await fetch(`${baseUrl}/workspaces/${id}`, { + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + return { id, error: `${response.status}` }; + } + + const data = await response.json(); + return data.workspace; +} + +// Known workspace IDs from agent profile +const workspaceIds = [2, 3, 4, 5, 6, 8, 9, 10, 11, 13]; +const specificId = process.argv[2]; + +try { + if (specificId) { + const workspace = await getWorkspace(parseInt(specificId)); + console.log(JSON.stringify(workspace, null, 2)); + } else { + const results = await Promise.all(workspaceIds.map(getWorkspace)); + const workspaces = results + .filter(w => !w.error) + .map(w => ({ + id: w.id, + name: w.name, + primary: w.primary, + state: w.state + })); + console.log(JSON.stringify({ workspaces }, null, 2)); + } +} catch (e) { + console.error(JSON.stringify({ error: e.message })); + process.exit(1); +} diff --git a/skills/freshservice-manager/scripts/list_agents.js b/skills/freshservice-manager/scripts/list_agents.js new file mode 100644 index 0000000..6b554f4 --- /dev/null +++ b/skills/freshservice-manager/scripts/list_agents.js @@ -0,0 +1,95 @@ +#!/usr/bin/env bun + +// List all agents +// Usage: bun list_agents.js [query] +// Query can be first name, last name, or email to filter + +import { readFileSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; + +function loadEnv() { + const envPath = join(homedir(), 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env'); + const content = readFileSync(envPath, 'utf-8'); + const env = {}; + for (const line of content.split('\n')) { + if (line && !line.startsWith('#')) { + const [key, ...valueParts] = line.split('='); + if (key && valueParts.length) { + env[key.trim()] = valueParts.join('=').trim(); + } + } + } + return env; +} + +const env = loadEnv(); +const domain = env.FRESHSERVICE_DOMAIN; +const apiKey = env.FRESHSERVICE_API_KEY; +const baseUrl = `https://${domain}/api/v2`; + +const query = process.argv[2]?.toLowerCase(); + +async function listAgents() { + let allAgents = []; + let page = 1; + let hasMore = true; + + while (hasMore) { + const response = await fetch(`${baseUrl}/agents?per_page=100&page=${page}`, { + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + const error = await response.text(); + return { error: `API error ${response.status}: ${error}` }; + } + + const data = await response.json(); + allAgents = allAgents.concat(data.agents); + + // Check if there are more pages + hasMore = data.agents.length === 100; + page++; + } + + // Filter and simplify + let agents = allAgents + .filter(a => a.active) + .map(a => ({ + id: a.id, + name: `${a.first_name} ${a.last_name}`, + first_name: a.first_name, + last_name: a.last_name, + email: a.email, + job_title: a.job_title + })); + + // Filter by query if provided + if (query) { + agents = agents.filter(a => + a.first_name.toLowerCase().includes(query) || + a.last_name.toLowerCase().includes(query) || + a.email.toLowerCase().includes(query) + ); + } + + // Sort by first name + agents.sort((a, b) => a.first_name.localeCompare(b.first_name)); + + return { + count: agents.length, + agents + }; +} + +try { + const result = await listAgents(); + console.log(JSON.stringify(result, null, 2)); +} catch (e) { + console.error(JSON.stringify({ error: e.message })); + process.exit(1); +} diff --git a/skills/freshservice-manager/scripts/list_tickets.js b/skills/freshservice-manager/scripts/list_tickets.js new file mode 100644 index 0000000..f37e516 --- /dev/null +++ b/skills/freshservice-manager/scripts/list_tickets.js @@ -0,0 +1,119 @@ +#!/usr/bin/env bun + +// List tickets with filters +// Usage: bun list_tickets.js [options] +// Options passed as JSON: {"workspace_id": 2, "filter": "open", "agent_id": 123, "per_page": 30} + +import { readFileSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; + +function loadEnv() { + const envPath = join(homedir(), 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env'); + const content = readFileSync(envPath, 'utf-8'); + const env = {}; + for (const line of content.split('\n')) { + if (line && !line.startsWith('#')) { + const [key, ...valueParts] = line.split('='); + if (key && valueParts.length) { + env[key.trim()] = valueParts.join('=').trim(); + } + } + } + return env; +} + +const env = loadEnv(); +const domain = env.FRESHSERVICE_DOMAIN; +const apiKey = env.FRESHSERVICE_API_KEY; +const baseUrl = `https://${domain}/api/v2`; + +// Parse options +let options = {}; +if (process.argv[2]) { + try { + options = JSON.parse(process.argv[2]); + } catch (e) { + console.error(JSON.stringify({ error: 'Invalid JSON options' })); + process.exit(1); + } +} + +async function listTickets(options) { + const params = new URLSearchParams(); + + // Workspace filter (0 = all workspaces) + if (options.workspace_id !== undefined) { + params.append('workspace_id', options.workspace_id); + } + + // Predefined filters: new_and_my_open, watching, spam, deleted + if (options.filter) { + params.append('filter', options.filter); + } + + // Include related data + if (options.include) { + params.append('include', options.include); + } + + // Pagination + params.append('per_page', options.per_page || 30); + if (options.page) { + params.append('page', options.page); + } + + // Order + if (options.order_type) { + params.append('order_type', options.order_type); + } + + // Updated since (for older tickets) + if (options.updated_since) { + params.append('updated_since', options.updated_since); + } + + const url = `${baseUrl}/tickets?${params.toString()}`; + + const response = await fetch(url, { + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + const error = await response.text(); + return { error: `API error ${response.status}: ${error}` }; + } + + const data = await response.json(); + + // Simplify output for readability + const tickets = data.tickets.map(t => ({ + id: t.id, + subject: t.subject, + status: t.status, + priority: t.priority, + requester_id: t.requester_id, + responder_id: t.responder_id, + group_id: t.group_id, + workspace_id: t.workspace_id, + created_at: t.created_at, + updated_at: t.updated_at, + due_by: t.due_by + })); + + return { + count: tickets.length, + tickets + }; +} + +try { + const result = await listTickets(options); + console.log(JSON.stringify(result, null, 2)); +} catch (e) { + console.error(JSON.stringify({ error: e.message })); + process.exit(1); +} diff --git a/skills/freshservice-manager/scripts/search_tickets.js b/skills/freshservice-manager/scripts/search_tickets.js new file mode 100644 index 0000000..b4a7114 --- /dev/null +++ b/skills/freshservice-manager/scripts/search_tickets.js @@ -0,0 +1,80 @@ +#!/usr/bin/env bun + +// Search tickets with query +// Usage: bun search_tickets.js '' [workspace_id] +// Query examples: "responder_id:123", "status:2 AND priority:3", "agent_id:123" + +import { readFileSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; + +function loadEnv() { + const envPath = join(homedir(), 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env'); + const content = readFileSync(envPath, 'utf-8'); + const env = {}; + for (const line of content.split('\n')) { + if (line && !line.startsWith('#')) { + const [key, ...valueParts] = line.split('='); + if (key && valueParts.length) { + env[key.trim()] = valueParts.join('=').trim(); + } + } + } + return env; +} + +const env = loadEnv(); +const domain = env.FRESHSERVICE_DOMAIN; +const apiKey = env.FRESHSERVICE_API_KEY; +const baseUrl = `https://${domain}/api/v2`; + +const query = process.argv[2]; +const workspaceId = process.argv[3] || '0'; + +if (!query) { + console.error(JSON.stringify({ error: 'Query required. Example: "responder_id:6000130414"' })); + process.exit(1); +} + +async function searchTickets(query, workspaceId) { + const url = `${baseUrl}/tickets/filter?query="${encodeURIComponent(query)}"&workspace_id=${workspaceId}`; + + const response = await fetch(url, { + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + const error = await response.text(); + return { error: `API error ${response.status}: ${error}` }; + } + + const data = await response.json(); + + const tickets = data.tickets.map(t => ({ + id: t.id, + subject: t.subject, + status: t.status, + priority: t.priority, + workspace_id: t.workspace_id, + responder_id: t.responder_id, + created_at: t.created_at, + updated_at: t.updated_at, + due_by: t.due_by + })); + + return { + count: tickets.length, + tickets + }; +} + +try { + const result = await searchTickets(query, workspaceId); + console.log(JSON.stringify(result, null, 2)); +} catch (e) { + console.error(JSON.stringify({ error: e.message })); + process.exit(1); +} diff --git a/skills/freshservice-manager/scripts/update_ticket.js b/skills/freshservice-manager/scripts/update_ticket.js new file mode 100644 index 0000000..48c38ec --- /dev/null +++ b/skills/freshservice-manager/scripts/update_ticket.js @@ -0,0 +1,74 @@ +#!/usr/bin/env bun + +// Update an existing ticket +// Usage: bun update_ticket.js '' +// JSON: {"status": 4, "priority": 3, "responder_id": 123, "group_id": 456} + +import { readFileSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; + +function loadEnv() { + const envPath = join(homedir(), 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env'); + const content = readFileSync(envPath, 'utf-8'); + const env = {}; + for (const line of content.split('\n')) { + if (line && !line.startsWith('#')) { + const [key, ...valueParts] = line.split('='); + if (key && valueParts.length) { + env[key.trim()] = valueParts.join('=').trim(); + } + } + } + return env; +} + +const env = loadEnv(); +const domain = env.FRESHSERVICE_DOMAIN; +const apiKey = env.FRESHSERVICE_API_KEY; +const baseUrl = `https://${domain}/api/v2`; + +// Status: 2=Open, 3=Pending, 4=Resolved, 5=Closed +// Priority: 1=Low, 2=Medium, 3=High, 4=Urgent + +const ticketId = process.argv[2]; +let updateData; + +if (!ticketId) { + console.error(JSON.stringify({ error: 'Ticket ID required' })); + process.exit(1); +} + +try { + updateData = JSON.parse(process.argv[3]); +} catch (e) { + console.error(JSON.stringify({ error: 'Invalid JSON for update data' })); + process.exit(1); +} + +async function updateTicket(id, data) { + const response = await fetch(`${baseUrl}/tickets/${id}`, { + method: 'PUT', + headers: { + 'Authorization': 'Basic ' + Buffer.from(`${apiKey}:X`).toString('base64'), + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }); + + if (!response.ok) { + const error = await response.text(); + return { error: `API error ${response.status}: ${error}` }; + } + + const result = await response.json(); + return result; +} + +try { + const result = await updateTicket(ticketId, updateData); + console.log(JSON.stringify(result, null, 2)); +} catch (e) { + console.error(JSON.stringify({ error: e.message })); + process.exit(1); +} diff --git a/skills/google-workspace/SKILL.md b/skills/google-workspace/SKILL.md new file mode 100644 index 0000000..0c7a3b2 --- /dev/null +++ b/skills/google-workspace/SKILL.md @@ -0,0 +1,190 @@ +--- +name: google-workspace +description: Unified Google Workspace integration for managing email, calendar, files, and communication across multiple accounts +triggers: + # Gmail + - "check email" + - "read email" + - "send email" + - "search email" + - "list emails" + - "unread emails" + - "inbox" + # Calendar + - "check calendar" + - "schedule meeting" + - "create event" + - "what's on my calendar" + - "free time" + - "upcoming meetings" + # Drive + - "find file" + - "search drive" + - "list documents" + - "open document" + - "create document" + # Docs/Sheets/Slides + - "create doc" + - "create spreadsheet" + - "create presentation" + - "edit document" + # Tasks + - "google tasks" + - "task list" + # Chat + - "send chat" + - "check chat" +allowed-tools: Read, Bash +version: 0.1.0 +--- + +# Google Workspace Skill + +## Overview + +Unified Google Workspace integration for managing email, calendar, files, and communication across three accounts: + +| Alias | Purpose | Email | +|-------|---------|-------| +| `psd` | Work | PSD district email | +| `kh` | Personal | Personal Gmail | +| `hrg` | Business | Consulting & real estate | + +## Account Selection + +### Explicit +- "check my **psd** email" +- "send email from **hrg**" +- "**kh** calendar for tomorrow" + +### Inferred +Geoffrey will infer the appropriate account from context: +- Work-related → `psd` +- Personal matters → `kh` +- Business/real estate → `hrg` + +## Available Operations + +### Gmail + +| Script | Description | Example | +|--------|-------------|---------| +| `list_messages.js` | List inbox, unread, by label | "show unread psd emails" | +| `read_message.js` | Get full message content | "read that email" | +| `send_message.js` | Compose and send | "send email to John about..." | +| `search_messages.js` | Search with Gmail operators | "find emails from Sarah last week" | + +### Calendar + +| Script | Description | Example | +|--------|-------------|---------| +| `list_events.js` | Get upcoming events | "what's on my calendar today" | +| `create_event.js` | Schedule new events | "schedule meeting tomorrow at 2pm" | +| `update_event.js` | Modify existing events | "move that meeting to 3pm" | +| `search_events.js` | Find by criteria | "find meetings with Mike" | + +### Drive + +| Script | Description | Example | +|--------|-------------|---------| +| `list_files.js` | Browse/search files | "find budget spreadsheet" | +| `read_file.js` | Get file content | "show me that document" | +| `create_file.js` | Create new docs/sheets | "create a new spreadsheet" | +| `upload_file.js` | Upload local file | "upload this to drive" | + +### Tasks + +| Script | Description | Example | +|--------|-------------|---------| +| `list_tasks.js` | Get task lists | "show my google tasks" | +| `create_task.js` | Add new task | "add task to google tasks" | +| `complete_task.js` | Mark done | "complete that task" | + +### Chat + +| Script | Description | Example | +|--------|-------------|---------| +| `list_spaces.js` | Get available spaces | "list chat spaces" | +| `send_message.js` | Post to space | "send message to team chat" | +| `read_messages.js` | Get chat history | "show recent chat messages" | + +## Usage Patterns + +### Running Scripts + +All scripts use the token_manager for authentication: + +```javascript +const { getAuthClient } = require('./auth/token_manager'); + +async function main() { + const account = process.argv[2] || 'psd'; + const auth = await getAuthClient(account); + + // Use auth with Google API + const gmail = google.gmail({ version: 'v1', auth }); + // ... +} +``` + +### Output Format + +All scripts return JSON: + +```json +{ + "success": true, + "account": "psd", + "data": { ... }, + "metadata": { + "timestamp": "2024-01-15T10:30:00Z", + "count": 5 + } +} +``` + +### Error Handling + +```json +{ + "error": "Token expired", + "account": "psd", + "action": "Run: node token_manager.js refresh psd" +} +``` + +## Setup Required + +Before using this skill: + +1. Complete Google Cloud Console setup (see `auth/GOOGLE_CLOUD_SETUP.md`) +2. Add credentials to `~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env` +3. Authenticate all three accounts +4. For PSD account: allowlist OAuth app in Google Admin + +## Cross-Account Operations + +Some operations work across accounts: +- "Forward this to my personal email" +- "Copy this file to my work drive" +- "Add to both calendars" + +## Gmail Search Operators + +Support standard Gmail search: +- `from:` - sender +- `to:` - recipient +- `subject:` - subject line +- `has:attachment` - with attachments +- `after:` / `before:` - date range +- `is:unread` - unread only +- `label:` - by label + +Example: "search psd email for `from:boss@psd.org after:2024-01-01 has:attachment`" + +## Notes + +- Access tokens expire after 1 hour (auto-refreshed) +- Refresh tokens don't expire unless revoked +- All API calls are rate-limited by Google +- Keep API has limited availability (may not be enabled) diff --git a/skills/google-workspace/auth/GOOGLE_CLOUD_SETUP.md b/skills/google-workspace/auth/GOOGLE_CLOUD_SETUP.md new file mode 100644 index 0000000..fee5c28 --- /dev/null +++ b/skills/google-workspace/auth/GOOGLE_CLOUD_SETUP.md @@ -0,0 +1,180 @@ +# Google Cloud Console Setup Guide + +## Step 1: Create Project + +1. Go to [Google Cloud Console](https://console.cloud.google.com/) +2. Sign in with your **consulting account** (this will own the OAuth app) +3. Click **Select a project** → **New Project** +4. Name: `Geoffrey Google Workspace` +5. Click **Create** + +## Step 2: Enable APIs + +Navigate to **APIs & Services → Library** and enable each: + +### Required APIs +- [ ] Gmail API +- [ ] Google Calendar API +- [ ] Google Drive API +- [ ] Google Docs API +- [ ] Google Sheets API +- [ ] Google Slides API +- [ ] Google Forms API +- [ ] Google Chat API +- [ ] Tasks API +- [ ] People API (for user info) + +### Optional APIs +- [ ] Google Keep API (limited availability) +- [ ] Gemini API (if using AI features) + +**Tip:** Search for each API name and click **Enable** + +## Step 3: Configure OAuth Consent Screen + +1. Go to **APIs & Services → OAuth consent screen** +2. Select **External** (unless all accounts are in same org) +3. Click **Create** + +### App Information +- App name: `Geoffrey` +- User support email: Your consulting email +- Developer contact: Your consulting email + +### Scopes +Click **Add or Remove Scopes** and add: + +``` +https://www.googleapis.com/auth/gmail.modify +https://www.googleapis.com/auth/calendar +https://www.googleapis.com/auth/drive +https://www.googleapis.com/auth/documents +https://www.googleapis.com/auth/spreadsheets +https://www.googleapis.com/auth/presentations +https://www.googleapis.com/auth/forms.body +https://www.googleapis.com/auth/chat.messages +https://www.googleapis.com/auth/tasks +https://www.googleapis.com/auth/userinfo.email +``` + +### Test Users +Add all three email addresses: +- Your PSD email +- Your personal email +- Your consulting email + +**Note:** While in "Testing" mode, only these users can authorize. + +## Step 4: Create OAuth Credentials + +1. Go to **APIs & Services → Credentials** +2. Click **Create Credentials → OAuth client ID** +3. Application type: **Desktop app** +4. Name: `Geoffrey CLI` +5. Click **Create** +6. Copy the **Client ID** and **Client Secret** +7. Add to your iCloud secrets `.env` file: + ``` + ~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env + ``` + + Add these lines: + ``` + GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com + GOOGLE_CLIENT_SECRET=your-client-secret + ``` + +## Step 5: PSD Domain Allowlisting + +Your PSD Google Workspace likely restricts third-party apps. To allow Geoffrey: + +### If You're a Google Admin: + +1. Go to [Google Admin Console](https://admin.google.com) +2. Navigate to **Security → Access and data control → API controls** +3. Click **Manage Third-Party App Access** +4. Click **Add app → OAuth App Name Or Client ID** +5. Enter your OAuth Client ID (from Step 4) +6. Select **Trusted** access + +### If You Need IT Approval: + +Send this to your IT team: + +``` +Subject: Request to Allow OAuth App for Personal Productivity Tool + +I need to allowlist a personal productivity app that integrates with Google Workspace. + +OAuth Client ID: [YOUR_CLIENT_ID_HERE] + +Requested scopes: +- Gmail (read/send) +- Calendar (read/write) +- Drive (read/write) +- Docs/Sheets/Slides (read/write) +- Tasks (read/write) + +This is a local CLI tool that runs only on my machine. +No data is sent to external servers. + +Please add this client ID to the trusted apps list. +``` + +## Step 6: Authenticate Each Account + +Once credentials are in your .env: + +```bash +cd skills/google-workspace + +# Install dependencies +bun install + +# Authenticate each account +bun auth/oauth_setup.js psd # Will open browser, sign in with PSD account +bun auth/oauth_setup.js kh # Will open browser, sign in with personal account +bun auth/oauth_setup.js hrg # Will open browser, sign in with consulting account + +# After each auth, store the tokens (copy the JSON output from oauth_setup) +bun auth/token_manager.js store psd '' +bun auth/token_manager.js store kh '' +bun auth/token_manager.js store hrg '' +``` + +## Step 7: Verify Setup + +```bash +# List stored accounts +bun auth/token_manager.js list + +# Test token retrieval +bun auth/token_manager.js get psd +``` + +## Troubleshooting + +### "Access blocked: This app's request is invalid" +- Check that redirect URI matches: `http://localhost:3000/oauth2callback` +- Verify OAuth consent screen is configured + +### "Access denied" for PSD account +- App needs to be allowlisted in PSD Google Admin +- Contact IT with the client ID + +### "Refresh token is null" +- Delete the app from your Google account's connected apps +- Re-run oauth_setup.js with the account +- The `prompt: 'consent'` should force a new refresh token + +### Token expires quickly +- Access tokens last 1 hour +- token_manager.js auto-refreshes using the refresh token +- Refresh tokens don't expire unless revoked + +## Security Notes + +- Credentials stored in iCloud secrets `.env` (synced, but local to your devices) +- Tokens stored in macOS Keychain (encrypted) +- Each account has its own isolated tokens +- Revoke access anytime from Google Account → Security → Third-party apps diff --git a/skills/google-workspace/auth/oauth_setup.js b/skills/google-workspace/auth/oauth_setup.js new file mode 100644 index 0000000..7165b3c --- /dev/null +++ b/skills/google-workspace/auth/oauth_setup.js @@ -0,0 +1,213 @@ +#!/usr/bin/env node + +/** + * OAuth2 Setup Script for Google Workspace + * + * Usage: node oauth_setup.js + * Example: node oauth_setup.js psd + * + * This script: + * 1. Starts a local server to receive OAuth callback + * 2. Opens browser to Google consent page + * 3. Exchanges auth code for tokens + * 4. Outputs tokens as JSON (to be stored by token_manager.js) + * + * Prerequisites: + * - .env file with GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET + * - npm install googleapis open dotenv + */ + +const { google } = require('googleapis'); +const http = require('http'); +const url = require('url'); +const openModule = require('open'); +const open = openModule.default || openModule; +const path = require('path'); + +// Load environment variables from iCloud secrets +const os = require('os'); +const ENV_PATH = path.join( + os.homedir(), + 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env' +); +require('dotenv').config({ path: ENV_PATH }); + +// Configuration +const REDIRECT_PORT = process.env.OAUTH_REDIRECT_PORT || 3000; +const REDIRECT_URI = `http://localhost:${REDIRECT_PORT}/oauth2callback`; + +// Full scope list for complete Google Workspace access +const SCOPES = [ + // Gmail + 'https://www.googleapis.com/auth/gmail.readonly', + 'https://www.googleapis.com/auth/gmail.send', + 'https://www.googleapis.com/auth/gmail.compose', + 'https://www.googleapis.com/auth/gmail.modify', + 'https://www.googleapis.com/auth/gmail.labels', + + // Calendar + 'https://www.googleapis.com/auth/calendar', + 'https://www.googleapis.com/auth/calendar.events', + + // Drive + 'https://www.googleapis.com/auth/drive', + 'https://www.googleapis.com/auth/drive.file', + + // Docs, Sheets, Slides + 'https://www.googleapis.com/auth/documents', + 'https://www.googleapis.com/auth/spreadsheets', + 'https://www.googleapis.com/auth/presentations', + + // Forms + 'https://www.googleapis.com/auth/forms.body', + 'https://www.googleapis.com/auth/forms.responses.readonly', + + // Chat + 'https://www.googleapis.com/auth/chat.spaces', + 'https://www.googleapis.com/auth/chat.messages', + 'https://www.googleapis.com/auth/chat.memberships.readonly', + + // Tasks + 'https://www.googleapis.com/auth/tasks', + + // Keep (Note: Keep API has limited availability) + // 'https://www.googleapis.com/auth/keep', + + // User info (to identify which account) + 'https://www.googleapis.com/auth/userinfo.email', + 'https://www.googleapis.com/auth/userinfo.profile', + + // Admin Directory (to look up user names) + 'https://www.googleapis.com/auth/admin.directory.user.readonly', +]; + +async function main() { + const accountAlias = process.argv[2]; + + if (!accountAlias) { + console.error(JSON.stringify({ + error: 'Missing account alias', + usage: 'node oauth_setup.js ', + example: 'node oauth_setup.js psd' + })); + process.exit(1); + } + + // Load client credentials from environment + const client_id = process.env.GOOGLE_CLIENT_ID; + const client_secret = process.env.GOOGLE_CLIENT_SECRET; + + if (!client_id || !client_secret) { + console.error(JSON.stringify({ + error: 'Missing credentials in .env', + instructions: [ + '1. Go to Google Cloud Console', + '2. Create OAuth 2.0 Client ID (Desktop app)', + '3. Copy client ID and secret to skills/google-workspace/.env', + '4. See .env.example for format' + ] + })); + process.exit(1); + } + + // Create OAuth2 client + const oauth2Client = new google.auth.OAuth2( + client_id, + client_secret, + REDIRECT_URI + ); + + // Generate auth URL + const authUrl = oauth2Client.generateAuthUrl({ + access_type: 'offline', + scope: SCOPES, + prompt: 'consent', // Force to get refresh token + }); + + // Start local server to receive callback + const server = http.createServer(async (req, res) => { + try { + const parsedUrl = url.parse(req.url, true); + + if (parsedUrl.pathname === '/oauth2callback') { + const code = parsedUrl.query.code; + + if (!code) { + res.writeHead(400); + res.end('Missing authorization code'); + return; + } + + // Exchange code for tokens + const { tokens } = await oauth2Client.getToken(code); + + // Get user info to confirm which account + oauth2Client.setCredentials(tokens); + const oauth2 = google.oauth2({ version: 'v2', auth: oauth2Client }); + const userInfo = await oauth2.userinfo.get(); + + // Send success response to browser + res.writeHead(200, { 'Content-Type': 'text/html' }); + res.end(` + + +

✅ Authorization Successful

+

Account: ${userInfo.data.email}

+

Alias: ${accountAlias}

+

You can close this window.

+ + + `); + + // Output tokens as JSON + console.log(JSON.stringify({ + success: true, + account: accountAlias, + email: userInfo.data.email, + tokens: { + access_token: tokens.access_token, + refresh_token: tokens.refresh_token, + token_type: tokens.token_type, + expiry_date: tokens.expiry_date, + } + }, null, 2)); + + // Close server + server.close(); + } + } catch (error) { + res.writeHead(500); + res.end('Authorization failed'); + console.error(JSON.stringify({ + error: 'Token exchange failed', + message: error.message + })); + server.close(); + process.exit(1); + } + }); + + server.listen(REDIRECT_PORT, async () => { + console.error(`Opening browser for ${accountAlias} account authorization...`); + console.error(`If browser doesn't open, visit: ${authUrl}`); + await open(authUrl); + }); + + // Timeout after 5 minutes + setTimeout(() => { + console.error(JSON.stringify({ + error: 'Authorization timeout', + message: 'No response received within 5 minutes' + })); + server.close(); + process.exit(1); + }, 5 * 60 * 1000); +} + +main().catch(error => { + console.error(JSON.stringify({ + error: 'Setup failed', + message: error.message + })); + process.exit(1); +}); diff --git a/skills/google-workspace/auth/token_manager.js b/skills/google-workspace/auth/token_manager.js new file mode 100644 index 0000000..42da75e --- /dev/null +++ b/skills/google-workspace/auth/token_manager.js @@ -0,0 +1,236 @@ +#!/usr/bin/env node + +/** + * Token Manager for Google Workspace + * + * Stores and retrieves OAuth tokens from macOS Keychain. + * + * Usage: + * Store: node token_manager.js store '' + * Retrieve: node token_manager.js get + * Refresh: node token_manager.js refresh + * List: node token_manager.js list + * Delete: node token_manager.js delete + * + * Examples: + * node token_manager.js store psd '{"access_token":"...","refresh_token":"..."}' + * node token_manager.js get psd + * node token_manager.js refresh psd + */ + +const { execSync } = require('child_process'); +const { google } = require('googleapis'); +const path = require('path'); + +// Load environment variables from iCloud secrets +const os = require('os'); +const ENV_PATH = path.join( + os.homedir(), + 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env' +); +require('dotenv').config({ path: ENV_PATH }); + +const SERVICE_NAME = 'geoffrey-google-workspace'; + +/** + * Store tokens in Keychain + */ +function storeTokens(account, tokens) { + const tokenString = typeof tokens === 'string' ? tokens : JSON.stringify(tokens); + + // Delete existing entry if present + try { + execSync( + `security delete-generic-password -s "${SERVICE_NAME}" -a "${account}" 2>/dev/null`, + { encoding: 'utf8' } + ); + } catch (e) { + // Entry might not exist, that's fine + } + + // Add new entry + try { + execSync( + `security add-generic-password -s "${SERVICE_NAME}" -a "${account}" -w '${tokenString.replace(/'/g, "'\\''")}' -U`, + { encoding: 'utf8' } + ); + return { success: true, account, message: 'Tokens stored in Keychain' }; + } catch (error) { + throw new Error(`Failed to store tokens: ${error.message}`); + } +} + +/** + * Retrieve tokens from Keychain + */ +function getTokens(account) { + try { + const result = execSync( + `security find-generic-password -s "${SERVICE_NAME}" -a "${account}" -w`, + { encoding: 'utf8' } + ).trim(); + return JSON.parse(result); + } catch (error) { + throw new Error(`No tokens found for account: ${account}`); + } +} + +/** + * Refresh access token using refresh token + */ +async function refreshTokens(account) { + // Get current tokens + const tokens = getTokens(account); + + if (!tokens.refresh_token) { + throw new Error('No refresh token available'); + } + + // Load credentials from environment + const client_id = process.env.GOOGLE_CLIENT_ID; + const client_secret = process.env.GOOGLE_CLIENT_SECRET; + + if (!client_id || !client_secret) { + throw new Error('Missing GOOGLE_CLIENT_ID or GOOGLE_CLIENT_SECRET in .env'); + } + + // Create OAuth2 client and refresh + const oauth2Client = new google.auth.OAuth2(client_id, client_secret); + oauth2Client.setCredentials(tokens); + + const { credentials: newTokens } = await oauth2Client.refreshAccessToken(); + + // Store updated tokens (keep refresh_token if not returned) + const updatedTokens = { + ...tokens, + access_token: newTokens.access_token, + expiry_date: newTokens.expiry_date, + }; + + storeTokens(account, updatedTokens); + + return { + success: true, + account, + access_token: newTokens.access_token, + expiry_date: newTokens.expiry_date + }; +} + +/** + * List all stored accounts + */ +function listAccounts() { + try { + const result = execSync( + `security dump-keychain | grep -A 4 '"svce"="${SERVICE_NAME}"' | grep '"acct"' | sed 's/.*="\\(.*\\)"/\\1/'`, + { encoding: 'utf8' } + ); + const accounts = result.trim().split('\n').filter(Boolean); + return { accounts }; + } catch (error) { + return { accounts: [] }; + } +} + +/** + * Delete tokens for an account + */ +function deleteTokens(account) { + try { + execSync( + `security delete-generic-password -s "${SERVICE_NAME}" -a "${account}"`, + { encoding: 'utf8' } + ); + return { success: true, account, message: 'Tokens deleted' }; + } catch (error) { + throw new Error(`Failed to delete tokens for ${account}: ${error.message}`); + } +} + +/** + * Get an authenticated OAuth2 client for an account + */ +async function getAuthClient(account) { + const tokens = getTokens(account); + + const client_id = process.env.GOOGLE_CLIENT_ID; + const client_secret = process.env.GOOGLE_CLIENT_SECRET; + + if (!client_id || !client_secret) { + throw new Error('Missing GOOGLE_CLIENT_ID or GOOGLE_CLIENT_SECRET in .env'); + } + + const oauth2Client = new google.auth.OAuth2(client_id, client_secret); + oauth2Client.setCredentials(tokens); + + // Check if token needs refresh (expires in next 5 minutes) + if (tokens.expiry_date && tokens.expiry_date < Date.now() + 5 * 60 * 1000) { + const refreshed = await refreshTokens(account); + oauth2Client.setCredentials({ + ...tokens, + access_token: refreshed.access_token + }); + } + + return oauth2Client; +} + +// CLI interface +async function main() { + const [command, account, data] = process.argv.slice(2); + + try { + let result; + + switch (command) { + case 'store': + if (!account || !data) { + throw new Error('Usage: token_manager.js store '); + } + result = storeTokens(account, JSON.parse(data)); + break; + + case 'get': + if (!account) { + throw new Error('Usage: token_manager.js get '); + } + result = getTokens(account); + break; + + case 'refresh': + if (!account) { + throw new Error('Usage: token_manager.js refresh '); + } + result = await refreshTokens(account); + break; + + case 'list': + result = listAccounts(); + break; + + case 'delete': + if (!account) { + throw new Error('Usage: token_manager.js delete '); + } + result = deleteTokens(account); + break; + + default: + throw new Error(`Unknown command: ${command}\nCommands: store, get, refresh, list, delete`); + } + + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ error: error.message })); + process.exit(1); + } +} + +// Only run CLI if called directly +if (require.main === module) { + main(); +} + +// Export for use by other scripts +module.exports = { getAuthClient, getTokens, refreshTokens, storeTokens }; diff --git a/skills/google-workspace/bun.lock b/skills/google-workspace/bun.lock new file mode 100644 index 0000000..e0157ed --- /dev/null +++ b/skills/google-workspace/bun.lock @@ -0,0 +1,182 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "geoffrey-google-workspace", + "dependencies": { + "dotenv": "^16.3.1", + "googleapis": "^128.0.0", + "open": "^9.1.0", + }, + }, + }, + "packages": { + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "big-integer": ["big-integer@1.6.52", "", {}, "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg=="], + + "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="], + + "bplist-parser": ["bplist-parser@0.2.0", "", { "dependencies": { "big-integer": "^1.6.44" } }, "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw=="], + + "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="], + + "bundle-name": ["bundle-name@3.0.0", "", { "dependencies": { "run-applescript": "^5.0.0" } }, "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "default-browser": ["default-browser@4.0.0", "", { "dependencies": { "bundle-name": "^3.0.0", "default-browser-id": "^3.0.0", "execa": "^7.1.1", "titleize": "^3.0.0" } }, "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA=="], + + "default-browser-id": ["default-browser-id@3.0.0", "", { "dependencies": { "bplist-parser": "^0.2.0", "untildify": "^4.0.0" } }, "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA=="], + + "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], + + "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "execa": ["execa@7.2.0", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", "human-signals": "^4.3.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^3.0.7", "strip-final-newline": "^3.0.0" } }, "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA=="], + + "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "gaxios": ["gaxios@6.7.1", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9", "uuid": "^9.0.1" } }, "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ=="], + + "gcp-metadata": ["gcp-metadata@6.1.1", "", { "dependencies": { "gaxios": "^6.1.1", "google-logging-utils": "^0.0.2", "json-bigint": "^1.0.0" } }, "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], + + "google-auth-library": ["google-auth-library@9.15.1", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^6.1.1", "gcp-metadata": "^6.1.0", "gtoken": "^7.0.0", "jws": "^4.0.0" } }, "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng=="], + + "google-logging-utils": ["google-logging-utils@0.0.2", "", {}, "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ=="], + + "googleapis": ["googleapis@128.0.0", "", { "dependencies": { "google-auth-library": "^9.0.0", "googleapis-common": "^7.0.0" } }, "sha512-+sLtVYNazcxaSD84N6rihVX4QiGoqRdnlz2SwmQQkadF31XonDfy4ufk3maMg27+FiySrH0rd7V8p+YJG6cknA=="], + + "googleapis-common": ["googleapis-common@7.2.0", "", { "dependencies": { "extend": "^3.0.2", "gaxios": "^6.0.3", "google-auth-library": "^9.7.0", "qs": "^6.7.0", "url-template": "^2.0.8", "uuid": "^9.0.0" } }, "sha512-/fhDZEJZvOV3X5jmD+fKxMqma5q2Q9nZNSF3kn1F18tpxmA86BcTxAGBQdM0N89Z3bEaIs+HVznSmFJEAmMTjA=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "gtoken": ["gtoken@7.1.0", "", { "dependencies": { "gaxios": "^6.0.0", "jws": "^4.0.0" } }, "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + + "human-signals": ["human-signals@4.3.1", "", {}, "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ=="], + + "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], + + "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], + + "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + + "is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="], + + "jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="], + + "jws": ["jws@4.0.0", "", { "dependencies": { "jwa": "^2.0.0", "safe-buffer": "^5.0.1" } }, "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], + + "mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + + "npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="], + + "open": ["open@9.1.0", "", { "dependencies": { "default-browser": "^4.0.0", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "is-wsl": "^2.2.0" } }, "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="], + + "run-applescript": ["run-applescript@5.0.0", "", { "dependencies": { "execa": "^5.0.0" } }, "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + + "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + + "strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="], + + "titleize": ["titleize@3.0.0", "", {}, "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ=="], + + "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + + "untildify": ["untildify@4.0.0", "", {}, "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw=="], + + "url-template": ["url-template@2.0.8", "", {}, "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw=="], + + "uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], + + "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + + "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], + + "is-wsl/is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], + + "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], + + "run-applescript/execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], + + "run-applescript/execa/human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], + + "run-applescript/execa/npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="], + + "run-applescript/execa/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], + + "run-applescript/execa/strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="], + + "run-applescript/execa/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], + } +} diff --git a/skills/google-workspace/calendar/create_event.js b/skills/google-workspace/calendar/create_event.js new file mode 100644 index 0000000..53e36d7 --- /dev/null +++ b/skills/google-workspace/calendar/create_event.js @@ -0,0 +1,163 @@ +#!/usr/bin/env node + +/** + * Create Calendar Event + * + * Usage: node create_event.js --summary --start <datetime> [options] + * + * Options: + * --summary Event title (required) + * --start Start datetime (required, ISO 8601 or natural) + * --end End datetime (default: 1 hour after start) + * --description Event description + * --location Event location + * --attendees Comma-separated email addresses + * --all-day Create all-day event (use date format for start/end) + * + * Examples: + * node create_event.js psd --summary "Team Meeting" --start "2024-01-15T14:00:00" + * node create_event.js personal --summary "Dinner" --start "2024-01-15T18:00:00" --end "2024-01-15T20:00:00" --location "Restaurant" + * node create_event.js consulting --summary "Client Call" --start "2024-01-15T10:00:00" --attendees "client@example.com" + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function createEvent(account, options) { + const auth = await getAuthClient(account); + const calendar = google.calendar({ version: 'v3', auth }); + + // Parse start time + const startDate = new Date(options.start); + if (isNaN(startDate.getTime())) { + throw new Error(`Invalid start date: ${options.start}`); + } + + // Calculate end time (default: 1 hour after start) + let endDate; + if (options.end) { + endDate = new Date(options.end); + if (isNaN(endDate.getTime())) { + throw new Error(`Invalid end date: ${options.end}`); + } + } else { + endDate = new Date(startDate); + endDate.setHours(endDate.getHours() + 1); + } + + // Build event + const event = { + summary: options.summary, + description: options.description, + location: options.location, + }; + + // Handle all-day vs timed events + if (options.allDay) { + event.start = { date: startDate.toISOString().split('T')[0] }; + event.end = { date: endDate.toISOString().split('T')[0] }; + } else { + event.start = { + dateTime: startDate.toISOString(), + timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone, + }; + event.end = { + dateTime: endDate.toISOString(), + timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone, + }; + } + + // Add attendees + if (options.attendees) { + event.attendees = options.attendees.split(',').map(email => ({ + email: email.trim(), + })); + } + + const response = await calendar.events.insert({ + calendarId: 'primary', + requestBody: event, + sendUpdates: options.attendees ? 'all' : 'none', + }); + + return { + success: true, + account, + event: { + id: response.data.id, + summary: response.data.summary, + start: response.data.start.dateTime || response.data.start.date, + end: response.data.end.dateTime || response.data.end.date, + htmlLink: response.data.htmlLink, + }, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + + if (!account) { + console.error(JSON.stringify({ + error: 'Missing account', + usage: 'node create_event.js <account> --summary <title> --start <datetime> [options]' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 1; i < args.length; i++) { + switch (args[i]) { + case '--summary': + options.summary = args[++i]; + break; + case '--start': + options.start = args[++i]; + break; + case '--end': + options.end = args[++i]; + break; + case '--description': + options.description = args[++i]; + break; + case '--location': + options.location = args[++i]; + break; + case '--attendees': + options.attendees = args[++i]; + break; + case '--all-day': + options.allDay = true; + break; + } + } + + if (!options.summary || !options.start) { + console.error(JSON.stringify({ + error: 'Missing required options: --summary, --start', + usage: 'node create_event.js <account> --summary <title> --start <datetime>' + })); + process.exit(1); + } + + try { + const result = await createEvent(account, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + })); + process.exit(1); + } +} + +main(); + +module.exports = { createEvent }; diff --git a/skills/google-workspace/calendar/list_events.js b/skills/google-workspace/calendar/list_events.js new file mode 100644 index 0000000..713c138 --- /dev/null +++ b/skills/google-workspace/calendar/list_events.js @@ -0,0 +1,124 @@ +#!/usr/bin/env node + +/** + * List Calendar Events + * + * Usage: node list_events.js <account> [options] + * + * Options: + * --days Number of days to look ahead (default: 7) + * --today Show only today's events + * --max Maximum events to return (default: 50) + * + * Examples: + * node list_events.js psd + * node list_events.js psd --today + * node list_events.js personal --days 30 + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function listEvents(account, options = {}) { + const auth = await getAuthClient(account); + const calendar = google.calendar({ version: 'v3', auth }); + + // Calculate time range + const now = new Date(); + const timeMin = new Date(now); + timeMin.setHours(0, 0, 0, 0); + + let timeMax; + if (options.today) { + timeMax = new Date(timeMin); + timeMax.setDate(timeMax.getDate() + 1); + } else { + timeMax = new Date(timeMin); + timeMax.setDate(timeMax.getDate() + (options.days || 7)); + } + + const response = await calendar.events.list({ + calendarId: 'primary', + timeMin: timeMin.toISOString(), + timeMax: timeMax.toISOString(), + maxResults: options.max || 50, + singleEvents: true, + orderBy: 'startTime', + }); + + const events = (response.data.items || []).map(event => ({ + id: event.id, + summary: event.summary, + description: event.description, + location: event.location, + start: event.start.dateTime || event.start.date, + end: event.end.dateTime || event.end.date, + isAllDay: !event.start.dateTime, + status: event.status, + attendees: (event.attendees || []).map(a => ({ + email: a.email, + name: a.displayName, + responseStatus: a.responseStatus, + })), + hangoutLink: event.hangoutLink, + htmlLink: event.htmlLink, + })); + + return { + success: true, + account, + events, + metadata: { + timestamp: new Date().toISOString(), + count: events.length, + timeMin: timeMin.toISOString(), + timeMax: timeMax.toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + + if (!account) { + console.error(JSON.stringify({ + error: 'Missing account', + usage: 'node list_events.js <account> [--today] [--days N] [--max N]' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 1; i < args.length; i++) { + switch (args[i]) { + case '--today': + options.today = true; + break; + case '--days': + options.days = parseInt(args[++i], 10); + break; + case '--max': + options.max = parseInt(args[++i], 10); + break; + } + } + + try { + const result = await listEvents(account, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + })); + process.exit(1); + } +} + +main(); + +module.exports = { listEvents }; diff --git a/skills/google-workspace/calendar/search_events.js b/skills/google-workspace/calendar/search_events.js new file mode 100644 index 0000000..635505d --- /dev/null +++ b/skills/google-workspace/calendar/search_events.js @@ -0,0 +1,124 @@ +#!/usr/bin/env node + +/** + * Search Calendar Events + * + * Usage: node search_events.js <account> <query> [options] + * + * Options: + * --days Number of days to search (default: 30) + * --max Maximum events to return (default: 50) + * + * Examples: + * node search_events.js psd "team meeting" + * node search_events.js personal "dinner" --days 60 + * node search_events.js consulting "client" + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function searchEvents(account, query, options = {}) { + const auth = await getAuthClient(account); + const calendar = google.calendar({ version: 'v3', auth }); + + // Calculate time range + const now = new Date(); + const timeMin = new Date(now); + timeMin.setDate(timeMin.getDate() - (options.days || 30)); // Look back too + + const timeMax = new Date(now); + timeMax.setDate(timeMax.getDate() + (options.days || 30)); + + const response = await calendar.events.list({ + calendarId: 'primary', + q: query, + timeMin: timeMin.toISOString(), + timeMax: timeMax.toISOString(), + maxResults: options.max || 50, + singleEvents: true, + orderBy: 'startTime', + }); + + const events = (response.data.items || []).map(event => ({ + id: event.id, + summary: event.summary, + description: event.description, + location: event.location, + start: event.start.dateTime || event.start.date, + end: event.end.dateTime || event.end.date, + isAllDay: !event.start.dateTime, + attendees: (event.attendees || []).map(a => ({ + email: a.email, + name: a.displayName, + responseStatus: a.responseStatus, + })), + htmlLink: event.htmlLink, + })); + + return { + success: true, + account, + query, + events, + metadata: { + timestamp: new Date().toISOString(), + count: events.length, + timeMin: timeMin.toISOString(), + timeMax: timeMax.toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + + if (!account) { + console.error(JSON.stringify({ + error: 'Missing account', + usage: 'node search_events.js <account> <query> [--days N] [--max N]' + })); + process.exit(1); + } + + // Find query (first non-flag argument after account) + let query = ''; + const options = {}; + + for (let i = 1; i < args.length; i++) { + if (args[i] === '--days') { + options.days = parseInt(args[++i], 10); + } else if (args[i] === '--max') { + options.max = parseInt(args[++i], 10); + } else if (!args[i].startsWith('--')) { + query = args[i]; + } + } + + if (!query) { + console.error(JSON.stringify({ + error: 'Missing query', + usage: 'node search_events.js <account> <query>' + })); + process.exit(1); + } + + try { + const result = await searchEvents(account, query, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + query, + })); + process.exit(1); + } +} + +main(); + +module.exports = { searchEvents }; diff --git a/skills/google-workspace/calendar/update_event.js b/skills/google-workspace/calendar/update_event.js new file mode 100644 index 0000000..a26ef00 --- /dev/null +++ b/skills/google-workspace/calendar/update_event.js @@ -0,0 +1,137 @@ +#!/usr/bin/env node + +/** + * Update Calendar Event + * + * Usage: node update_event.js <account> <event-id> [options] + * + * Options: + * --summary New event title + * --start New start datetime + * --end New end datetime + * --description New description + * --location New location + * + * Examples: + * node update_event.js psd abc123 --start "2024-01-15T15:00:00" + * node update_event.js personal def456 --summary "Updated Meeting" --location "New Room" + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function updateEvent(account, eventId, options) { + const auth = await getAuthClient(account); + const calendar = google.calendar({ version: 'v3', auth }); + + // Get existing event + const existing = await calendar.events.get({ + calendarId: 'primary', + eventId, + }); + + const event = existing.data; + + // Update fields + if (options.summary) event.summary = options.summary; + if (options.description) event.description = options.description; + if (options.location) event.location = options.location; + + if (options.start) { + const startDate = new Date(options.start); + if (isNaN(startDate.getTime())) { + throw new Error(`Invalid start date: ${options.start}`); + } + event.start = { + dateTime: startDate.toISOString(), + timeZone: event.start.timeZone || Intl.DateTimeFormat().resolvedOptions().timeZone, + }; + } + + if (options.end) { + const endDate = new Date(options.end); + if (isNaN(endDate.getTime())) { + throw new Error(`Invalid end date: ${options.end}`); + } + event.end = { + dateTime: endDate.toISOString(), + timeZone: event.end.timeZone || Intl.DateTimeFormat().resolvedOptions().timeZone, + }; + } + + const response = await calendar.events.update({ + calendarId: 'primary', + eventId, + requestBody: event, + sendUpdates: event.attendees ? 'all' : 'none', + }); + + return { + success: true, + account, + event: { + id: response.data.id, + summary: response.data.summary, + start: response.data.start.dateTime || response.data.start.date, + end: response.data.end.dateTime || response.data.end.date, + htmlLink: response.data.htmlLink, + }, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + const eventId = args[1]; + + if (!account || !eventId) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'node update_event.js <account> <event-id> [options]' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 2; i < args.length; i++) { + switch (args[i]) { + case '--summary': + options.summary = args[++i]; + break; + case '--start': + options.start = args[++i]; + break; + case '--end': + options.end = args[++i]; + break; + case '--description': + options.description = args[++i]; + break; + case '--location': + options.location = args[++i]; + break; + } + } + + try { + const result = await updateEvent(account, eventId, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + eventId, + })); + process.exit(1); + } +} + +main(); + +module.exports = { updateEvent }; diff --git a/skills/google-workspace/chat/list_spaces.js b/skills/google-workspace/chat/list_spaces.js new file mode 100644 index 0000000..86d3ac7 --- /dev/null +++ b/skills/google-workspace/chat/list_spaces.js @@ -0,0 +1,91 @@ +#!/usr/bin/env node + +/** + * List Google Chat Spaces + * + * Usage: node list_spaces.js <account> + * + * Examples: + * node list_spaces.js psd + * node list_spaces.js kh + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function listSpaces(account) { + const auth = await getAuthClient(account); + const chat = google.chat({ version: 'v1', auth }); + + const response = await chat.spaces.list({ + pageSize: 100, + }); + + // Get read state for each space to find unreads + const spacesWithState = await Promise.all( + (response.data.spaces || []).map(async space => { + try { + // Get space read state + const stateResponse = await chat.spaces.spaceReadState.get({ + name: `${space.name}/spaceReadState`, + }); + return { + name: space.name, + displayName: space.displayName, + type: space.type, + spaceType: space.spaceType, + lastReadTime: stateResponse.data.lastReadTime, + }; + } catch (e) { + return { + name: space.name, + displayName: space.displayName, + type: space.type, + spaceType: space.spaceType, + lastReadTime: null, + }; + } + }) + ); + + const spaces = spacesWithState; + + return { + success: true, + account, + spaces, + metadata: { + timestamp: new Date().toISOString(), + count: spaces.length, + } + }; +} + +// CLI interface +async function main() { + const account = process.argv[2]; + + if (!account) { + console.error(JSON.stringify({ + error: 'Missing account', + usage: 'node list_spaces.js <account>' + })); + process.exit(1); + } + + try { + const result = await listSpaces(account); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + })); + process.exit(1); + } +} + +main(); + +module.exports = { listSpaces }; diff --git a/skills/google-workspace/chat/read_messages.js b/skills/google-workspace/chat/read_messages.js new file mode 100644 index 0000000..19da606 --- /dev/null +++ b/skills/google-workspace/chat/read_messages.js @@ -0,0 +1,128 @@ +#!/usr/bin/env node + +/** + * Read Google Chat Messages from a Space + * + * Usage: node read_messages.js <account> <space-name> [options] + * + * Options: + * --max Maximum messages to return (default: 50) + * + * Examples: + * node read_messages.js psd spaces/AAAA1234567 + * node read_messages.js psd spaces/AAAA1234567 --max 100 + */ + +const { google } = require('googleapis'); +const path = require('path'); +const fs = require('fs'); +const os = require('os'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +// Load user mapping from iCloud preferences +let allUserMappings = {}; +const mappingPath = path.join( + os.homedir(), + 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/knowledge/chat_user_mapping.json' +); +if (fs.existsSync(mappingPath)) { + try { + allUserMappings = JSON.parse(fs.readFileSync(mappingPath, 'utf8')); + } catch (e) { + // Ignore errors + } +} + +async function readMessages(account, spaceName, options = {}) { + const auth = await getAuthClient(account); + const chat = google.chat({ version: 'v1', auth }); + + // Get space members to build userId -> displayName mapping + const membersResponse = await chat.spaces.members.list({ + parent: spaceName, + pageSize: 100, + }); + + const userNameMap = {}; + for (const membership of (membersResponse.data.memberships || [])) { + if (membership.member && membership.member.name) { + const userId = membership.member.name; + userNameMap[userId] = membership.member.displayName || userId; + } + } + + const response = await chat.spaces.messages.list({ + parent: spaceName, + pageSize: options.max || 50, + orderBy: 'createTime desc', + }); + + // Get account-specific user mapping + const userMapping = allUserMappings[account] || {}; + + const messages = (response.data.messages || []).map(msg => { + const senderId = msg.sender?.name; + const bareId = senderId?.replace('users/', ''); + const senderName = userMapping[bareId] || userNameMap[senderId] || msg.sender?.displayName || senderId; + + return { + name: msg.name, + sender: senderName, + senderId: bareId, + senderType: msg.sender?.type, + text: msg.text, + createTime: msg.createTime, + threadName: msg.thread?.name, + }; + }); + + return { + success: true, + account, + spaceName, + messages, + metadata: { + timestamp: new Date().toISOString(), + count: messages.length, + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + const spaceName = args[1]; + + if (!account || !spaceName) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'node read_messages.js <account> <space-name> [--max N]' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 2; i < args.length; i++) { + if (args[i] === '--max') { + options.max = parseInt(args[++i], 10); + } + } + + try { + const result = await readMessages(account, spaceName, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + spaceName, + })); + process.exit(1); + } +} + +main(); + +module.exports = { readMessages }; diff --git a/skills/google-workspace/chat/send_message.js b/skills/google-workspace/chat/send_message.js new file mode 100644 index 0000000..249f640 --- /dev/null +++ b/skills/google-workspace/chat/send_message.js @@ -0,0 +1,106 @@ +#!/usr/bin/env node + +/** + * Send Google Chat Message + * + * Usage: node send_message.js <account> <space-name> --text <message> + * + * Options: + * --text Message text (required) + * --thread Thread name to reply to (optional) + * + * Examples: + * node send_message.js psd spaces/AAAA1234567 --text "Hello team!" + * node send_message.js psd spaces/AAAA1234567 --text "Reply" --thread spaces/AAAA/threads/BBBB + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function sendMessage(account, spaceName, options) { + const auth = await getAuthClient(account); + const chat = google.chat({ version: 'v1', auth }); + + const requestBody = { + text: options.text, + }; + + if (options.thread) { + requestBody.thread = { + name: options.thread, + }; + } + + const response = await chat.spaces.messages.create({ + parent: spaceName, + requestBody, + }); + + return { + success: true, + account, + message: { + name: response.data.name, + text: response.data.text, + createTime: response.data.createTime, + space: spaceName, + thread: response.data.thread?.name, + }, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + const spaceName = args[1]; + + if (!account || !spaceName) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'node send_message.js <account> <space-name> --text <message>' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 2; i < args.length; i++) { + switch (args[i]) { + case '--text': + options.text = args[++i]; + break; + case '--thread': + options.thread = args[++i]; + break; + } + } + + if (!options.text) { + console.error(JSON.stringify({ + error: 'Missing --text option', + usage: 'node send_message.js <account> <space-name> --text <message>' + })); + process.exit(1); + } + + try { + const result = await sendMessage(account, spaceName, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + spaceName, + })); + process.exit(1); + } +} + +main(); + +module.exports = { sendMessage }; diff --git a/skills/google-workspace/docs/create_doc.js b/skills/google-workspace/docs/create_doc.js new file mode 100644 index 0000000..a279f1b --- /dev/null +++ b/skills/google-workspace/docs/create_doc.js @@ -0,0 +1,155 @@ +#!/usr/bin/env node + +/** + * Create Google Doc with Markdown Formatting + * + * Usage: bun create_doc.js <account> --title <title> [options] + * + * Options: + * --title Document title (required) + * --content Markdown content + * --folder Subfolder in Geoffrey (Research, Notes, Reports, Travel) + * --raw Don't apply markdown formatting (plain text) + * + * Examples: + * bun create_doc.js hrg --title "Meeting Notes" --folder Notes + * bun create_doc.js psd --title "Report" --content "# Header\n\nContent" --folder Research + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); +const { ensureGeoffreyFolders } = require(path.join(__dirname, '..', 'utils', 'folder_manager')); +const { insertFormattedContent } = require(path.join(__dirname, '..', 'utils', 'markdown_to_docs')); + +async function createDoc(account, options) { + const auth = await getAuthClient(account); + const docs = google.docs({ version: 'v1', auth }); + const drive = google.drive({ version: 'v3', auth }); + + // Get or create Geoffrey folder structure + let folderId = null; + if (options.folder) { + const folderResult = await ensureGeoffreyFolders(account, options.folder); + folderId = folderResult.targetFolder; + } + + // Create the document + const createResponse = await docs.documents.create({ + requestBody: { + title: options.title, + }, + }); + + const documentId = createResponse.data.documentId; + + // Move to Geoffrey folder if specified + if (folderId) { + // Get current parents + const file = await drive.files.get({ + fileId: documentId, + fields: 'parents', + }); + + // Move to Geoffrey folder + await drive.files.update({ + fileId: documentId, + addParents: folderId, + removeParents: file.data.parents.join(','), + fields: 'id, parents', + }); + } + + // Add content if provided + let formattingInfo = null; + if (options.content) { + if (options.raw) { + // Plain text insertion + await docs.documents.batchUpdate({ + documentId, + requestBody: { + requests: [{ + insertText: { + location: { index: 1 }, + text: options.content, + }, + }], + }, + }); + } else { + // Markdown formatted insertion + formattingInfo = await insertFormattedContent(docs, documentId, options.content); + } + } + + return { + success: true, + account, + document: { + id: documentId, + title: createResponse.data.title, + url: `https://docs.google.com/document/d/${documentId}/edit`, + folder: options.folder || 'root', + }, + formatting: formattingInfo, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + + if (!account) { + console.error(JSON.stringify({ + error: 'Missing account', + usage: 'bun create_doc.js <account> --title <title> [--content <markdown>] [--folder <subfolder>]' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 1; i < args.length; i++) { + switch (args[i]) { + case '--title': + options.title = args[++i]; + break; + case '--content': + options.content = args[++i]; + break; + case '--folder': + options.folder = args[++i]; + break; + case '--raw': + options.raw = true; + break; + } + } + + if (!options.title) { + console.error(JSON.stringify({ + error: 'Missing --title option', + usage: 'bun create_doc.js <account> --title <title> [--content <markdown>] [--folder <subfolder>]' + })); + process.exit(1); + } + + try { + const result = await createDoc(account, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + })); + process.exit(1); + } +} + +main(); + +module.exports = { createDoc }; diff --git a/skills/google-workspace/docs/edit_doc.js b/skills/google-workspace/docs/edit_doc.js new file mode 100644 index 0000000..58d0d1f --- /dev/null +++ b/skills/google-workspace/docs/edit_doc.js @@ -0,0 +1,282 @@ +#!/usr/bin/env node + +/** + * Edit Google Doc with Markdown Formatting + * + * Usage: bun edit_doc.js <account> <document-id> --append <markdown> + * bun edit_doc.js <account> <document-id> --replace <old> --with <new> + * + * Options: + * --raw Don't apply markdown formatting (plain text) + * + * Examples: + * bun edit_doc.js psd DOC_ID --append "## New Section\n\nContent here" + * bun edit_doc.js psd DOC_ID --append "Plain text" --raw + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); +const { parseMarkdown } = require(path.join(__dirname, '..', 'utils', 'markdown_to_docs')); + +/** + * Parse markdown with custom start index (for appending) + */ +function parseMarkdownAtIndex(markdown, startIndex) { + const requests = []; + let plainText = ''; + let currentIndex = startIndex; + + const lines = markdown.split('\n'); + + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + + // Horizontal rule + if (line.match(/^---+$/)) { + const ruleLine = '─'.repeat(50) + '\n'; + plainText += ruleLine; + currentIndex += ruleLine.length; + continue; + } + + // Headers + const headerMatch = line.match(/^(#{1,6})\s+(.+)$/); + if (headerMatch) { + const level = headerMatch[1].length; + const headerContent = headerMatch[2]; + const { plainText: processedText, requests: inlineRequests } = + processInlineFormattingAtIndex(headerContent, currentIndex); + + const fullLine = processedText + '\n'; + const headingStyle = level === 1 ? 'HEADING_1' : + level === 2 ? 'HEADING_2' : + level === 3 ? 'HEADING_3' : 'HEADING_4'; + + requests.push({ + updateParagraphStyle: { + range: { startIndex: currentIndex, endIndex: currentIndex + fullLine.length }, + paragraphStyle: { namedStyleType: headingStyle }, + fields: 'namedStyleType', + }, + }); + requests.push(...inlineRequests); + plainText += fullLine; + currentIndex += fullLine.length; + continue; + } + + // Bullet lists + const bulletMatch = line.match(/^[-*]\s+(.+)$/); + if (bulletMatch) { + const { plainText: processedText, requests: inlineRequests } = + processInlineFormattingAtIndex(bulletMatch[1], currentIndex + 2); + const fullLine = '• ' + processedText + '\n'; + plainText += fullLine; + requests.push(...inlineRequests); + currentIndex += fullLine.length; + continue; + } + + // Numbered lists + const numberedMatch = line.match(/^(\d+)\.\s+(.+)$/); + if (numberedMatch) { + const prefix = numberedMatch[1] + '. '; + const { plainText: processedText, requests: inlineRequests } = + processInlineFormattingAtIndex(numberedMatch[2], currentIndex + prefix.length); + const fullLine = prefix + processedText + '\n'; + plainText += fullLine; + requests.push(...inlineRequests); + currentIndex += fullLine.length; + continue; + } + + // Regular line + const { plainText: processedText, requests: inlineRequests } = + processInlineFormattingAtIndex(line, currentIndex); + const fullLine = processedText + '\n'; + plainText += fullLine; + requests.push(...inlineRequests); + currentIndex += fullLine.length; + } + + return { text: plainText, requests }; +} + +function processInlineFormattingAtIndex(text, startIndex) { + const requests = []; + let plainText = ''; + let charIndex = startIndex; + let remaining = text; + + while (remaining.length > 0) { + const boldMatch = remaining.match(/^\*\*(.+?)\*\*/); + if (boldMatch) { + plainText += boldMatch[1]; + requests.push({ + updateTextStyle: { + range: { startIndex: charIndex, endIndex: charIndex + boldMatch[1].length }, + textStyle: { bold: true }, + fields: 'bold', + }, + }); + charIndex += boldMatch[1].length; + remaining = remaining.substring(boldMatch[0].length); + continue; + } + + const linkMatch = remaining.match(/^\[([^\]]+)\]\(([^)]+)\)/); + if (linkMatch) { + plainText += linkMatch[1]; + requests.push({ + updateTextStyle: { + range: { startIndex: charIndex, endIndex: charIndex + linkMatch[1].length }, + textStyle: { link: { url: linkMatch[2] } }, + fields: 'link', + }, + }); + charIndex += linkMatch[1].length; + remaining = remaining.substring(linkMatch[0].length); + continue; + } + + plainText += remaining[0]; + charIndex++; + remaining = remaining.substring(1); + } + + return { plainText, requests }; +} + +async function editDoc(account, documentId, options) { + const auth = await getAuthClient(account); + const docs = google.docs({ version: 'v1', auth }); + + if (options.append) { + // Get document to find end index + const doc = await docs.documents.get({ documentId }); + const endIndex = doc.data.body.content[doc.data.body.content.length - 1].endIndex - 1; + + if (options.raw) { + // Plain text append + await docs.documents.batchUpdate({ + documentId, + requestBody: { + requests: [{ + insertText: { + location: { index: endIndex }, + text: '\n' + options.append, + }, + }], + }, + }); + return { + success: true, + account, + documentId, + updates: 1, + metadata: { timestamp: new Date().toISOString() } + }; + } + + // Formatted append + const { text, requests } = parseMarkdownAtIndex(options.append, endIndex + 1); + + // Insert text + await docs.documents.batchUpdate({ + documentId, + requestBody: { + requests: [{ + insertText: { + location: { index: endIndex }, + text: '\n' + text, + }, + }], + }, + }); + + // Apply formatting + if (requests.length > 0) { + await docs.documents.batchUpdate({ + documentId, + requestBody: { requests }, + }); + } + + return { + success: true, + account, + documentId, + updates: 1 + requests.length, + formatting: { textLength: text.length, formattingRequests: requests.length }, + metadata: { timestamp: new Date().toISOString() } + }; + } + + if (options.replace && options.with) { + await docs.documents.batchUpdate({ + documentId, + requestBody: { + requests: [{ + replaceAllText: { + containsText: { text: options.replace, matchCase: true }, + replaceText: options.with, + }, + }], + }, + }); + + return { + success: true, + account, + documentId, + updates: 1, + metadata: { timestamp: new Date().toISOString() } + }; + } + + return { success: false, error: 'No edit operation specified' }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + const documentId = args[1]; + + if (!account || !documentId) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'bun edit_doc.js <account> <document-id> --append <markdown>' + })); + process.exit(1); + } + + const options = {}; + for (let i = 2; i < args.length; i++) { + switch (args[i]) { + case '--append': options.append = args[++i]; break; + case '--replace': options.replace = args[++i]; break; + case '--with': options.with = args[++i]; break; + case '--raw': options.raw = true; break; + } + } + + try { + const result = await editDoc(account, documentId, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + documentId, + })); + process.exit(1); + } +} + +if (require.main === module) { + main(); +} + +module.exports = { editDoc }; diff --git a/skills/google-workspace/docs/read_doc.js b/skills/google-workspace/docs/read_doc.js new file mode 100644 index 0000000..5700f1c --- /dev/null +++ b/skills/google-workspace/docs/read_doc.js @@ -0,0 +1,87 @@ +#!/usr/bin/env node + +/** + * Read Google Doc Content + * + * Usage: node read_doc.js <account> <document-id> + * + * Examples: + * node read_doc.js psd 1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function readDoc(account, documentId) { + const auth = await getAuthClient(account); + const docs = google.docs({ version: 'v1', auth }); + + const response = await docs.documents.get({ + documentId, + }); + + const doc = response.data; + + // Extract text content from document body + let textContent = ''; + if (doc.body && doc.body.content) { + for (const element of doc.body.content) { + if (element.paragraph && element.paragraph.elements) { + for (const textElement of element.paragraph.elements) { + if (textElement.textRun && textElement.textRun.content) { + textContent += textElement.textRun.content; + } + } + } + if (element.table) { + textContent += '[TABLE]\n'; + } + } + } + + return { + success: true, + account, + document: { + id: doc.documentId, + title: doc.title, + textContent: textContent.trim(), + revisionId: doc.revisionId, + }, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + const documentId = args[1]; + + if (!account || !documentId) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'node read_doc.js <account> <document-id>' + })); + process.exit(1); + } + + try { + const result = await readDoc(account, documentId); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + documentId, + })); + process.exit(1); + } +} + +main(); + +module.exports = { readDoc }; diff --git a/skills/google-workspace/drive/create_file.js b/skills/google-workspace/drive/create_file.js new file mode 100644 index 0000000..88e9e5b --- /dev/null +++ b/skills/google-workspace/drive/create_file.js @@ -0,0 +1,140 @@ +#!/usr/bin/env node + +/** + * Create Drive File (Google Docs, Sheets, Slides) + * + * Usage: node create_file.js <account> --name <name> --type <type> [options] + * + * Options: + * --name File name (required) + * --type File type: doc, sheet, slide (required) + * --content Initial content (for docs) + * --folder Parent folder ID + * + * Examples: + * node create_file.js psd --name "Meeting Notes" --type doc + * node create_file.js personal --name "Budget 2024" --type sheet + * node create_file.js consulting --name "Proposal" --type slide --folder 1abc123 + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +const MIME_TYPES = { + doc: 'application/vnd.google-apps.document', + sheet: 'application/vnd.google-apps.spreadsheet', + slide: 'application/vnd.google-apps.presentation', +}; + +async function createFile(account, options) { + const auth = await getAuthClient(account); + const drive = google.drive({ version: 'v3', auth }); + + const mimeType = MIME_TYPES[options.type]; + if (!mimeType) { + throw new Error(`Invalid type: ${options.type}. Use: doc, sheet, slide`); + } + + const fileMetadata = { + name: options.name, + mimeType, + }; + + if (options.folder) { + fileMetadata.parents = [options.folder]; + } + + const response = await drive.files.create({ + requestBody: fileMetadata, + fields: 'id, name, mimeType, webViewLink', + }); + + const file = response.data; + + // If content provided for doc, update it + if (options.content && options.type === 'doc') { + const docs = google.docs({ version: 'v1', auth }); + await docs.documents.batchUpdate({ + documentId: file.id, + requestBody: { + requests: [{ + insertText: { + location: { index: 1 }, + text: options.content, + } + }] + } + }); + } + + return { + success: true, + account, + file: { + id: file.id, + name: file.name, + mimeType: file.mimeType, + webLink: file.webViewLink, + }, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + + if (!account) { + console.error(JSON.stringify({ + error: 'Missing account', + usage: 'node create_file.js <account> --name <name> --type doc|sheet|slide [options]' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 1; i < args.length; i++) { + switch (args[i]) { + case '--name': + options.name = args[++i]; + break; + case '--type': + options.type = args[++i]; + break; + case '--content': + options.content = args[++i]; + break; + case '--folder': + options.folder = args[++i]; + break; + } + } + + if (!options.name || !options.type) { + console.error(JSON.stringify({ + error: 'Missing required options: --name, --type', + usage: 'node create_file.js <account> --name <name> --type doc|sheet|slide' + })); + process.exit(1); + } + + try { + const result = await createFile(account, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + })); + process.exit(1); + } +} + +main(); + +module.exports = { createFile }; diff --git a/skills/google-workspace/drive/download_file.js b/skills/google-workspace/drive/download_file.js new file mode 100644 index 0000000..ebe0aa5 --- /dev/null +++ b/skills/google-workspace/drive/download_file.js @@ -0,0 +1,92 @@ +#!/usr/bin/env node + +/** + * Download Drive File + * + * Downloads a file from Google Drive to local filesystem. + * + * Usage: bun download_file.js <account> <fileId> <outputPath> + */ + +const { google } = require('googleapis'); +const fs = require('fs'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function downloadFile(account, fileId, outputPath) { + const auth = await getAuthClient(account); + const drive = google.drive({ version: 'v3', auth }); + + // Get file metadata first + const fileInfo = await drive.files.get({ + fileId, + fields: 'name, mimeType', + supportsAllDrives: true + }); + + // Download file content + const response = await drive.files.get( + { fileId, alt: 'media', supportsAllDrives: true }, + { responseType: 'stream' } + ); + + // Ensure output directory exists + const outputDir = path.dirname(outputPath); + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + + // Write to file + const dest = fs.createWriteStream(outputPath); + + return new Promise((resolve, reject) => { + response.data + .on('end', () => { + resolve({ + success: true, + account, + file: { + id: fileId, + name: fileInfo.data.name, + mimeType: fileInfo.data.mimeType, + outputPath + } + }); + }) + .on('error', err => { + reject(err); + }) + .pipe(dest); + }); +} + +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + const fileId = args[1]; + const outputPath = args[2]; + + if (!account || !fileId || !outputPath) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'bun download_file.js <account> <fileId> <outputPath>' + })); + process.exit(1); + } + + try { + const result = await downloadFile(account, fileId, outputPath); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + fileId + })); + process.exit(1); + } +} + +main(); + +module.exports = { downloadFile }; diff --git a/skills/google-workspace/drive/list_files.js b/skills/google-workspace/drive/list_files.js new file mode 100644 index 0000000..bbb1bf4 --- /dev/null +++ b/skills/google-workspace/drive/list_files.js @@ -0,0 +1,133 @@ +#!/usr/bin/env node + +/** + * List Drive Files + * + * Usage: node list_files.js <account> [options] + * + * Options: + * --query Search query (Drive search syntax) + * --type File type: doc, sheet, slide, pdf, folder + * --max Maximum files to return (default: 20) + * --folder Folder ID to list contents of + * + * Examples: + * node list_files.js psd + * node list_files.js psd --query "budget" + * node list_files.js personal --type sheet + * node list_files.js consulting --type pdf --query "contract" + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +const MIME_TYPES = { + doc: 'application/vnd.google-apps.document', + sheet: 'application/vnd.google-apps.spreadsheet', + slide: 'application/vnd.google-apps.presentation', + pdf: 'application/pdf', + folder: 'application/vnd.google-apps.folder', +}; + +async function listFiles(account, options = {}) { + const auth = await getAuthClient(account); + const drive = google.drive({ version: 'v3', auth }); + + // Build query + const queryParts = []; + + if (options.query) { + queryParts.push(`fullText contains '${options.query}'`); + } + + if (options.type && MIME_TYPES[options.type]) { + queryParts.push(`mimeType = '${MIME_TYPES[options.type]}'`); + } + + if (options.folder) { + queryParts.push(`'${options.folder}' in parents`); + } + + // Exclude trashed files + queryParts.push('trashed = false'); + + const response = await drive.files.list({ + q: queryParts.join(' and '), + pageSize: options.max || 20, + fields: 'files(id, name, mimeType, size, createdTime, modifiedTime, webViewLink, parents)', + orderBy: 'modifiedTime desc', + supportsAllDrives: true, + includeItemsFromAllDrives: true, + }); + + const files = (response.data.files || []).map(file => ({ + id: file.id, + name: file.name, + mimeType: file.mimeType, + size: file.size, + created: file.createdTime, + modified: file.modifiedTime, + webLink: file.webViewLink, + parents: file.parents, + })); + + return { + success: true, + account, + files, + metadata: { + timestamp: new Date().toISOString(), + count: files.length, + query: options.query || '(all)', + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + + if (!account) { + console.error(JSON.stringify({ + error: 'Missing account', + usage: 'node list_files.js <account> [--query "..."] [--type doc|sheet|slide|pdf|folder] [--max N]' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 1; i < args.length; i++) { + switch (args[i]) { + case '--query': + options.query = args[++i]; + break; + case '--type': + options.type = args[++i]; + break; + case '--max': + options.max = parseInt(args[++i], 10); + break; + case '--folder': + options.folder = args[++i]; + break; + } + } + + try { + const result = await listFiles(account, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + })); + process.exit(1); + } +} + +main(); + +module.exports = { listFiles }; diff --git a/skills/google-workspace/drive/read_file.js b/skills/google-workspace/drive/read_file.js new file mode 100644 index 0000000..40f1bc7 --- /dev/null +++ b/skills/google-workspace/drive/read_file.js @@ -0,0 +1,130 @@ +#!/usr/bin/env node + +/** + * Read Drive File Content + * + * Usage: node read_file.js <account> <file-id> [options] + * + * Options: + * --format Export format for Google Docs (text, html, pdf) + * + * Examples: + * node read_file.js psd 1abc123def456 + * node read_file.js personal 1xyz789 --format html + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +const EXPORT_FORMATS = { + 'application/vnd.google-apps.document': { + text: 'text/plain', + html: 'text/html', + pdf: 'application/pdf', + }, + 'application/vnd.google-apps.spreadsheet': { + csv: 'text/csv', + pdf: 'application/pdf', + }, + 'application/vnd.google-apps.presentation': { + text: 'text/plain', + pdf: 'application/pdf', + }, +}; + +async function readFile(account, fileId, options = {}) { + const auth = await getAuthClient(account); + const drive = google.drive({ version: 'v3', auth }); + + // Get file metadata + const metadata = await drive.files.get({ + fileId, + fields: 'id, name, mimeType, size, webViewLink', + supportsAllDrives: true, + }); + + const file = metadata.data; + let content = ''; + + // Check if it's a Google Workspace file (needs export) + if (file.mimeType.startsWith('application/vnd.google-apps.')) { + const exportFormats = EXPORT_FORMATS[file.mimeType]; + if (exportFormats) { + const format = options.format || 'text'; + const mimeType = exportFormats[format] || exportFormats.text || Object.values(exportFormats)[0]; + + const response = await drive.files.export({ + fileId, + mimeType, + }, { responseType: 'text' }); + + content = response.data; + } else { + content = '[Cannot export this file type]'; + } + } else { + // Regular file - download content + const response = await drive.files.get({ + fileId, + alt: 'media', + supportsAllDrives: true, + }, { responseType: 'text' }); + + content = response.data; + } + + return { + success: true, + account, + file: { + id: file.id, + name: file.name, + mimeType: file.mimeType, + webLink: file.webViewLink, + content, + }, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + const fileId = args[1]; + + if (!account || !fileId) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'node read_file.js <account> <file-id> [--format text|html|pdf]' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 2; i < args.length; i++) { + if (args[i] === '--format') { + options.format = args[++i]; + } + } + + try { + const result = await readFile(account, fileId, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + fileId, + })); + process.exit(1); + } +} + +main(); + +module.exports = { readFile }; diff --git a/skills/google-workspace/gmail/list_messages.js b/skills/google-workspace/gmail/list_messages.js new file mode 100644 index 0000000..44fe8c6 --- /dev/null +++ b/skills/google-workspace/gmail/list_messages.js @@ -0,0 +1,154 @@ +#!/usr/bin/env node + +/** + * List Gmail Messages + * + * Usage: node list_messages.js <account> [options] + * + * Options: + * --query Gmail search query (default: empty = all) + * --label Filter by label (e.g., INBOX, UNREAD, SENT) + * --max Maximum messages to return (default: 10) + * --unread Show only unread messages + * + * Examples: + * node list_messages.js psd + * node list_messages.js psd --unread --max 5 + * node list_messages.js personal --query "from:amazon.com" + * node list_messages.js consulting --label SENT + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function listMessages(account, options = {}) { + const auth = await getAuthClient(account); + const gmail = google.gmail({ version: 'v1', auth }); + + // Build query + let query = options.query || ''; + if (options.unread) { + query = query ? `${query} is:unread` : 'is:unread'; + } + + // List messages + const listParams = { + userId: 'me', + maxResults: options.max || 10, + }; + + if (query) { + listParams.q = query; + } + + if (options.label) { + listParams.labelIds = [options.label.toUpperCase()]; + } + + const response = await gmail.users.messages.list(listParams); + const messages = response.data.messages || []; + + if (messages.length === 0) { + return { + success: true, + account, + messages: [], + metadata: { + timestamp: new Date().toISOString(), + count: 0, + query: query || '(all)', + } + }; + } + + // Get message details + const messageDetails = await Promise.all( + messages.map(async (msg) => { + const detail = await gmail.users.messages.get({ + userId: 'me', + id: msg.id, + format: 'metadata', + metadataHeaders: ['From', 'To', 'Subject', 'Date'], + }); + + const headers = detail.data.payload.headers; + const getHeader = (name) => { + const header = headers.find(h => h.name.toLowerCase() === name.toLowerCase()); + return header ? header.value : ''; + }; + + return { + id: msg.id, + threadId: msg.threadId, + from: getHeader('From'), + to: getHeader('To'), + subject: getHeader('Subject'), + date: getHeader('Date'), + snippet: detail.data.snippet, + labels: detail.data.labelIds, + isUnread: detail.data.labelIds.includes('UNREAD'), + }; + }) + ); + + return { + success: true, + account, + messages: messageDetails, + metadata: { + timestamp: new Date().toISOString(), + count: messageDetails.length, + query: query || '(all)', + nextPageToken: response.data.nextPageToken, + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + + if (!account) { + console.error(JSON.stringify({ + error: 'Missing account', + usage: 'node list_messages.js <account> [--unread] [--query "..."] [--max N] [--label LABEL]' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 1; i < args.length; i++) { + switch (args[i]) { + case '--unread': + options.unread = true; + break; + case '--query': + options.query = args[++i]; + break; + case '--max': + options.max = parseInt(args[++i], 10); + break; + case '--label': + options.label = args[++i]; + break; + } + } + + try { + const result = await listMessages(account, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + })); + process.exit(1); + } +} + +main(); + +module.exports = { listMessages }; diff --git a/skills/google-workspace/gmail/read_message.js b/skills/google-workspace/gmail/read_message.js new file mode 100644 index 0000000..fca9ccf --- /dev/null +++ b/skills/google-workspace/gmail/read_message.js @@ -0,0 +1,126 @@ +#!/usr/bin/env node + +/** + * Read Gmail Message + * + * Usage: node read_message.js <account> <message-id> + * + * Examples: + * node read_message.js psd 18d1234567890abc + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function readMessage(account, messageId) { + const auth = await getAuthClient(account); + const gmail = google.gmail({ version: 'v1', auth }); + + const response = await gmail.users.messages.get({ + userId: 'me', + id: messageId, + format: 'full', + }); + + const message = response.data; + const headers = message.payload.headers; + + const getHeader = (name) => { + const header = headers.find(h => h.name.toLowerCase() === name.toLowerCase()); + return header ? header.value : ''; + }; + + // Extract body + let body = ''; + let htmlBody = ''; + + function extractBody(payload) { + if (payload.body && payload.body.data) { + const decoded = Buffer.from(payload.body.data, 'base64').toString('utf8'); + if (payload.mimeType === 'text/plain') { + body = decoded; + } else if (payload.mimeType === 'text/html') { + htmlBody = decoded; + } + } + + if (payload.parts) { + for (const part of payload.parts) { + extractBody(part); + } + } + } + + extractBody(message.payload); + + // Get attachments info + const attachments = []; + function findAttachments(payload) { + if (payload.filename && payload.body && payload.body.attachmentId) { + attachments.push({ + filename: payload.filename, + mimeType: payload.mimeType, + size: payload.body.size, + attachmentId: payload.body.attachmentId, + }); + } + if (payload.parts) { + for (const part of payload.parts) { + findAttachments(part); + } + } + } + + findAttachments(message.payload); + + return { + success: true, + account, + message: { + id: message.id, + threadId: message.threadId, + from: getHeader('From'), + to: getHeader('To'), + cc: getHeader('Cc'), + subject: getHeader('Subject'), + date: getHeader('Date'), + body: body || htmlBody, + isHtml: !body && !!htmlBody, + labels: message.labelIds, + attachments, + }, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const [account, messageId] = process.argv.slice(2); + + if (!account || !messageId) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'node read_message.js <account> <message-id>' + })); + process.exit(1); + } + + try { + const result = await readMessage(account, messageId); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + messageId, + })); + process.exit(1); + } +} + +main(); + +module.exports = { readMessage }; diff --git a/skills/google-workspace/gmail/search_messages.js b/skills/google-workspace/gmail/search_messages.js new file mode 100644 index 0000000..eb6963c --- /dev/null +++ b/skills/google-workspace/gmail/search_messages.js @@ -0,0 +1,130 @@ +#!/usr/bin/env node + +/** + * Search Gmail Messages + * + * Usage: node search_messages.js <account> <query> + * + * Supports all Gmail search operators: + * from: - Sender + * to: - Recipient + * subject: - Subject line + * has:attachment - Has attachments + * after: - After date (YYYY/MM/DD) + * before: - Before date + * is:unread - Unread only + * is:starred - Starred only + * label: - By label + * filename: - Attachment filename + * + * Examples: + * node search_messages.js psd "from:boss@psd.org" + * node search_messages.js personal "subject:invoice after:2024/01/01" + * node search_messages.js consulting "has:attachment from:client" + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function searchMessages(account, query, maxResults = 20) { + const auth = await getAuthClient(account); + const gmail = google.gmail({ version: 'v1', auth }); + + const response = await gmail.users.messages.list({ + userId: 'me', + q: query, + maxResults, + }); + + const messages = response.data.messages || []; + + if (messages.length === 0) { + return { + success: true, + account, + query, + messages: [], + metadata: { + timestamp: new Date().toISOString(), + count: 0, + } + }; + } + + // Get message details + const messageDetails = await Promise.all( + messages.map(async (msg) => { + const detail = await gmail.users.messages.get({ + userId: 'me', + id: msg.id, + format: 'metadata', + metadataHeaders: ['From', 'To', 'Subject', 'Date'], + }); + + const headers = detail.data.payload.headers; + const getHeader = (name) => { + const header = headers.find(h => h.name.toLowerCase() === name.toLowerCase()); + return header ? header.value : ''; + }; + + return { + id: msg.id, + threadId: msg.threadId, + from: getHeader('From'), + to: getHeader('To'), + subject: getHeader('Subject'), + date: getHeader('Date'), + snippet: detail.data.snippet, + labels: detail.data.labelIds, + isUnread: detail.data.labelIds.includes('UNREAD'), + }; + }) + ); + + return { + success: true, + account, + query, + messages: messageDetails, + metadata: { + timestamp: new Date().toISOString(), + count: messageDetails.length, + nextPageToken: response.data.nextPageToken, + } + }; +} + +// CLI interface +async function main() { + const [account, ...queryParts] = process.argv.slice(2); + const query = queryParts.join(' '); + + if (!account || !query) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'node search_messages.js <account> <query>', + examples: [ + 'node search_messages.js psd "from:boss@psd.org"', + 'node search_messages.js personal "subject:invoice after:2024/01/01"', + ] + })); + process.exit(1); + } + + try { + const result = await searchMessages(account, query); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + query, + })); + process.exit(1); + } +} + +main(); + +module.exports = { searchMessages }; diff --git a/skills/google-workspace/gmail/send_message.js b/skills/google-workspace/gmail/send_message.js new file mode 100644 index 0000000..822b5a6 --- /dev/null +++ b/skills/google-workspace/gmail/send_message.js @@ -0,0 +1,175 @@ +#!/usr/bin/env node + +/** + * Send Gmail Message + * + * Usage: node send_message.js <account> --to <email> --subject <subject> --body <body> + * + * Options: + * --to Recipient email (required) + * --subject Email subject (required) + * --body Email body (required) + * --cc CC recipients (comma-separated) + * --bcc BCC recipients (comma-separated) + * --reply-to Message ID to reply to + * + * Examples: + * node send_message.js psd --to "john@example.com" --subject "Hello" --body "Message here" + * node send_message.js personal --to "friend@gmail.com" --subject "Lunch?" --body "Are you free?" --cc "other@gmail.com" + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function sendMessage(account, options) { + const auth = await getAuthClient(account); + const gmail = google.gmail({ version: 'v1', auth }); + + // Get sender email + const profile = await gmail.users.getProfile({ userId: 'me' }); + const fromEmail = profile.data.emailAddress; + + // Build email + const emailLines = [ + `From: ${fromEmail}`, + `To: ${options.to}`, + ]; + + if (options.cc) { + emailLines.push(`Cc: ${options.cc}`); + } + + if (options.bcc) { + emailLines.push(`Bcc: ${options.bcc}`); + } + + emailLines.push( + `Subject: ${options.subject}`, + 'Content-Type: text/plain; charset=utf-8', + '', + options.body + ); + + // If replying, add thread info + if (options.replyTo) { + const original = await gmail.users.messages.get({ + userId: 'me', + id: options.replyTo, + format: 'metadata', + metadataHeaders: ['Message-ID', 'References'], + }); + + const headers = original.data.payload.headers; + const messageIdHeader = headers.find(h => h.name === 'Message-ID'); + const referencesHeader = headers.find(h => h.name === 'References'); + + if (messageIdHeader) { + const references = referencesHeader + ? `${referencesHeader.value} ${messageIdHeader.value}` + : messageIdHeader.value; + emailLines.splice(2, 0, `In-Reply-To: ${messageIdHeader.value}`); + emailLines.splice(3, 0, `References: ${references}`); + } + } + + const email = emailLines.join('\r\n'); + const encodedEmail = Buffer.from(email).toString('base64') + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, ''); + + const sendParams = { + userId: 'me', + requestBody: { + raw: encodedEmail, + }, + }; + + if (options.replyTo) { + const original = await gmail.users.messages.get({ + userId: 'me', + id: options.replyTo, + format: 'minimal', + }); + sendParams.requestBody.threadId = original.data.threadId; + } + + const response = await gmail.users.messages.send(sendParams); + + return { + success: true, + account, + sent: { + id: response.data.id, + threadId: response.data.threadId, + to: options.to, + subject: options.subject, + }, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + + if (!account) { + console.error(JSON.stringify({ + error: 'Missing account', + usage: 'node send_message.js <account> --to <email> --subject <subject> --body <body>' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 1; i < args.length; i++) { + switch (args[i]) { + case '--to': + options.to = args[++i]; + break; + case '--subject': + options.subject = args[++i]; + break; + case '--body': + options.body = args[++i]; + break; + case '--cc': + options.cc = args[++i]; + break; + case '--bcc': + options.bcc = args[++i]; + break; + case '--reply-to': + options.replyTo = args[++i]; + break; + } + } + + if (!options.to || !options.subject || !options.body) { + console.error(JSON.stringify({ + error: 'Missing required options: --to, --subject, --body', + usage: 'node send_message.js <account> --to <email> --subject <subject> --body <body>' + })); + process.exit(1); + } + + try { + const result = await sendMessage(account, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + })); + process.exit(1); + } +} + +main(); + +module.exports = { sendMessage }; diff --git a/skills/google-workspace/package.json b/skills/google-workspace/package.json new file mode 100644 index 0000000..d56088c --- /dev/null +++ b/skills/google-workspace/package.json @@ -0,0 +1,17 @@ +{ + "name": "geoffrey-google-workspace", + "version": "1.0.0", + "description": "Google Workspace integration for Geoffrey", + "private": true, + "scripts": { + "setup:psd": "bun auth/oauth_setup.js psd", + "setup:kh": "bun auth/oauth_setup.js kh", + "setup:hrg": "bun auth/oauth_setup.js hrg", + "list:accounts": "bun auth/token_manager.js list" + }, + "dependencies": { + "dotenv": "^16.3.1", + "googleapis": "^128.0.0", + "open": "^9.1.0" + } +} diff --git a/skills/google-workspace/sheets/create_sheet.js b/skills/google-workspace/sheets/create_sheet.js new file mode 100644 index 0000000..67d3b93 --- /dev/null +++ b/skills/google-workspace/sheets/create_sheet.js @@ -0,0 +1,102 @@ +#!/usr/bin/env node + +/** + * Create Google Sheet + * + * Usage: node create_sheet.js <account> --title <title> [--sheets <sheet1,sheet2>] + * + * Examples: + * node create_sheet.js psd --title "Budget 2025" + * node create_sheet.js psd --title "Project Tracker" --sheets "Tasks,Timeline,Resources" + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function createSheet(account, options) { + const auth = await getAuthClient(account); + const sheets = google.sheets({ version: 'v4', auth }); + + const requestBody = { + properties: { + title: options.title, + }, + }; + + // Add custom sheets if specified + if (options.sheets) { + const sheetNames = options.sheets.split(',').map(s => s.trim()); + requestBody.sheets = sheetNames.map(name => ({ + properties: { title: name }, + })); + } + + const response = await sheets.spreadsheets.create({ + requestBody, + }); + + return { + success: true, + account, + spreadsheet: { + id: response.data.spreadsheetId, + title: response.data.properties.title, + url: response.data.spreadsheetUrl, + sheets: response.data.sheets.map(s => s.properties.title), + }, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + + if (!account) { + console.error(JSON.stringify({ + error: 'Missing account', + usage: 'node create_sheet.js <account> --title <title> [--sheets <sheet1,sheet2>]' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 1; i < args.length; i++) { + switch (args[i]) { + case '--title': + options.title = args[++i]; + break; + case '--sheets': + options.sheets = args[++i]; + break; + } + } + + if (!options.title) { + console.error(JSON.stringify({ + error: 'Missing --title option', + usage: 'node create_sheet.js <account> --title <title> [--sheets <sheet1,sheet2>]' + })); + process.exit(1); + } + + try { + const result = await createSheet(account, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + })); + process.exit(1); + } +} + +main(); + +module.exports = { createSheet }; diff --git a/skills/google-workspace/sheets/edit_sheet.js b/skills/google-workspace/sheets/edit_sheet.js new file mode 100644 index 0000000..d06257f --- /dev/null +++ b/skills/google-workspace/sheets/edit_sheet.js @@ -0,0 +1,99 @@ +#!/usr/bin/env node + +/** + * Edit Google Sheet + * + * Usage: node edit_sheet.js <account> <spreadsheet-id> --range <range> --values <json-array> + * + * Examples: + * node edit_sheet.js psd SHEET_ID --range "A1" --values '[["Hello"]]' + * node edit_sheet.js psd SHEET_ID --range "A1:B2" --values '[["Name","Score"],["Alice",100]]' + * node edit_sheet.js psd SHEET_ID --range "Sheet2!A1" --values '[["Data"]]' + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function editSheet(account, spreadsheetId, options) { + const auth = await getAuthClient(account); + const sheets = google.sheets({ version: 'v4', auth }); + + const values = JSON.parse(options.values); + + const response = await sheets.spreadsheets.values.update({ + spreadsheetId, + range: options.range, + valueInputOption: 'USER_ENTERED', + requestBody: { + values, + }, + }); + + return { + success: true, + account, + spreadsheetId, + update: { + range: response.data.updatedRange, + rowsUpdated: response.data.updatedRows, + columnsUpdated: response.data.updatedColumns, + cellsUpdated: response.data.updatedCells, + }, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + const spreadsheetId = args[1]; + + if (!account || !spreadsheetId) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'node edit_sheet.js <account> <spreadsheet-id> --range <range> --values <json-array>' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 2; i < args.length; i++) { + switch (args[i]) { + case '--range': + options.range = args[++i]; + break; + case '--values': + options.values = args[++i]; + break; + } + } + + if (!options.range || !options.values) { + console.error(JSON.stringify({ + error: 'Missing --range or --values option', + usage: 'node edit_sheet.js <account> <spreadsheet-id> --range <range> --values <json-array>' + })); + process.exit(1); + } + + try { + const result = await editSheet(account, spreadsheetId, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + spreadsheetId, + })); + process.exit(1); + } +} + +main(); + +module.exports = { editSheet }; diff --git a/skills/google-workspace/sheets/read_sheet.js b/skills/google-workspace/sheets/read_sheet.js new file mode 100644 index 0000000..5aa6c51 --- /dev/null +++ b/skills/google-workspace/sheets/read_sheet.js @@ -0,0 +1,89 @@ +#!/usr/bin/env node + +/** + * Read Google Sheet Data + * + * Usage: node read_sheet.js <account> <spreadsheet-id> [--range <range>] + * + * Examples: + * node read_sheet.js psd 1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms + * node read_sheet.js psd SHEET_ID --range "Sheet1!A1:D10" + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function readSheet(account, spreadsheetId, options = {}) { + const auth = await getAuthClient(account); + const sheets = google.sheets({ version: 'v4', auth }); + + // Get spreadsheet metadata + const metadata = await sheets.spreadsheets.get({ + spreadsheetId, + }); + + // Get values + const range = options.range || metadata.data.sheets[0].properties.title; + const response = await sheets.spreadsheets.values.get({ + spreadsheetId, + range, + }); + + return { + success: true, + account, + spreadsheet: { + id: spreadsheetId, + title: metadata.data.properties.title, + sheets: metadata.data.sheets.map(s => s.properties.title), + }, + data: { + range: response.data.range, + values: response.data.values || [], + rowCount: (response.data.values || []).length, + }, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + const spreadsheetId = args[1]; + + if (!account || !spreadsheetId) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'node read_sheet.js <account> <spreadsheet-id> [--range <range>]' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 2; i < args.length; i++) { + if (args[i] === '--range') { + options.range = args[++i]; + } + } + + try { + const result = await readSheet(account, spreadsheetId, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + spreadsheetId, + })); + process.exit(1); + } +} + +main(); + +module.exports = { readSheet }; diff --git a/skills/google-workspace/slides/create_presentation.js b/skills/google-workspace/slides/create_presentation.js new file mode 100644 index 0000000..36497e6 --- /dev/null +++ b/skills/google-workspace/slides/create_presentation.js @@ -0,0 +1,84 @@ +#!/usr/bin/env node + +/** + * Create Google Slides Presentation + * + * Usage: node create_presentation.js <account> --title <title> + * + * Examples: + * node create_presentation.js psd --title "Q4 Review" + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function createPresentation(account, options) { + const auth = await getAuthClient(account); + const slides = google.slides({ version: 'v1', auth }); + + const response = await slides.presentations.create({ + requestBody: { + title: options.title, + }, + }); + + return { + success: true, + account, + presentation: { + id: response.data.presentationId, + title: response.data.title, + url: `https://docs.google.com/presentation/d/${response.data.presentationId}/edit`, + slideCount: (response.data.slides || []).length, + }, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + + if (!account) { + console.error(JSON.stringify({ + error: 'Missing account', + usage: 'node create_presentation.js <account> --title <title>' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 1; i < args.length; i++) { + if (args[i] === '--title') { + options.title = args[++i]; + } + } + + if (!options.title) { + console.error(JSON.stringify({ + error: 'Missing --title option', + usage: 'node create_presentation.js <account> --title <title>' + })); + process.exit(1); + } + + try { + const result = await createPresentation(account, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + })); + process.exit(1); + } +} + +main(); + +module.exports = { createPresentation }; diff --git a/skills/google-workspace/slides/edit_presentation.js b/skills/google-workspace/slides/edit_presentation.js new file mode 100644 index 0000000..028ec08 --- /dev/null +++ b/skills/google-workspace/slides/edit_presentation.js @@ -0,0 +1,174 @@ +#!/usr/bin/env node + +/** + * Edit Google Slides Presentation + * + * Usage: node edit_presentation.js <account> <presentation-id> <action> [options] + * + * Actions: + * --add-slide Add a blank slide + * --add-text-slide Add slide with title and body + * --replace-text Replace text across presentation + * + * Examples: + * node edit_presentation.js psd PRES_ID --add-slide + * node edit_presentation.js psd PRES_ID --add-text-slide --title "Agenda" --body "Item 1\nItem 2" + * node edit_presentation.js psd PRES_ID --replace-text --find "2024" --replace "2025" + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function editPresentation(account, presentationId, options) { + const auth = await getAuthClient(account); + const slides = google.slides({ version: 'v1', auth }); + + const requests = []; + + if (options.addSlide) { + requests.push({ + createSlide: { + slideLayoutReference: { + predefinedLayout: 'BLANK', + }, + }, + }); + } + + if (options.addTextSlide) { + const slideId = `slide_${Date.now()}`; + const titleId = `title_${Date.now()}`; + const bodyId = `body_${Date.now()}`; + + requests.push({ + createSlide: { + objectId: slideId, + slideLayoutReference: { + predefinedLayout: 'TITLE_AND_BODY', + }, + placeholderIdMappings: [ + { + layoutPlaceholder: { type: 'TITLE' }, + objectId: titleId, + }, + { + layoutPlaceholder: { type: 'BODY' }, + objectId: bodyId, + }, + ], + }, + }); + + if (options.title) { + requests.push({ + insertText: { + objectId: titleId, + text: options.title, + }, + }); + } + + if (options.body) { + requests.push({ + insertText: { + objectId: bodyId, + text: options.body, + }, + }); + } + } + + if (options.replaceText && options.find && options.replace) { + requests.push({ + replaceAllText: { + containsText: { + text: options.find, + matchCase: true, + }, + replaceText: options.replace, + }, + }); + } + + if (requests.length === 0) { + return { + success: false, + error: 'No edit operation specified', + }; + } + + const response = await slides.presentations.batchUpdate({ + presentationId, + requestBody: { requests }, + }); + + return { + success: true, + account, + presentationId, + updates: response.data.replies.length, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + const presentationId = args[1]; + + if (!account || !presentationId) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'node edit_presentation.js <account> <presentation-id> --add-slide' + })); + process.exit(1); + } + + // Parse options + const options = {}; + for (let i = 2; i < args.length; i++) { + switch (args[i]) { + case '--add-slide': + options.addSlide = true; + break; + case '--add-text-slide': + options.addTextSlide = true; + break; + case '--replace-text': + options.replaceText = true; + break; + case '--title': + options.title = args[++i]; + break; + case '--body': + options.body = args[++i]; + break; + case '--find': + options.find = args[++i]; + break; + case '--replace': + options.replace = args[++i]; + break; + } + } + + try { + const result = await editPresentation(account, presentationId, options); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + presentationId, + })); + process.exit(1); + } +} + +main(); + +module.exports = { editPresentation }; diff --git a/skills/google-workspace/slides/read_presentation.js b/skills/google-workspace/slides/read_presentation.js new file mode 100644 index 0000000..c6cced0 --- /dev/null +++ b/skills/google-workspace/slides/read_presentation.js @@ -0,0 +1,93 @@ +#!/usr/bin/env node + +/** + * Read Google Slides Presentation + * + * Usage: node read_presentation.js <account> <presentation-id> + * + * Examples: + * node read_presentation.js psd 1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +async function readPresentation(account, presentationId) { + const auth = await getAuthClient(account); + const slides = google.slides({ version: 'v1', auth }); + + const response = await slides.presentations.get({ + presentationId, + }); + + const presentation = response.data; + + // Extract slide content + const slideContent = (presentation.slides || []).map((slide, index) => { + const texts = []; + + // Extract text from page elements + for (const element of (slide.pageElements || [])) { + if (element.shape && element.shape.text) { + for (const textElement of (element.shape.text.textElements || [])) { + if (textElement.textRun && textElement.textRun.content) { + const text = textElement.textRun.content.trim(); + if (text) texts.push(text); + } + } + } + } + + return { + slideNumber: index + 1, + objectId: slide.objectId, + texts, + }; + }); + + return { + success: true, + account, + presentation: { + id: presentation.presentationId, + title: presentation.title, + slideCount: (presentation.slides || []).length, + slides: slideContent, + }, + metadata: { + timestamp: new Date().toISOString(), + } + }; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + const presentationId = args[1]; + + if (!account || !presentationId) { + console.error(JSON.stringify({ + error: 'Missing arguments', + usage: 'node read_presentation.js <account> <presentation-id>' + })); + process.exit(1); + } + + try { + const result = await readPresentation(account, presentationId); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + presentationId, + })); + process.exit(1); + } +} + +main(); + +module.exports = { readPresentation }; diff --git a/skills/google-workspace/utils/folder_manager.js b/skills/google-workspace/utils/folder_manager.js new file mode 100644 index 0000000..c2bf88a --- /dev/null +++ b/skills/google-workspace/utils/folder_manager.js @@ -0,0 +1,123 @@ +#!/usr/bin/env node + +/** + * Geoffrey Folder Manager + * + * Ensures Geoffrey folder structure exists in Google Drive. + * Creates folders if they don't exist, returns folder IDs. + * + * Usage: bun folder_manager.js <account> [subfolder] + * + * Examples: + * bun folder_manager.js hrg # Get/create Geoffrey folder + * bun folder_manager.js hrg Research # Get/create Geoffrey/Research + */ + +const { google } = require('googleapis'); +const path = require('path'); +const { getAuthClient } = require(path.join(__dirname, '..', 'auth', 'token_manager')); + +const GEOFFREY_FOLDER = 'Geoffrey'; +const SUBFOLDERS = ['Research', 'Notes', 'Reports', 'Travel']; + +async function findFolder(drive, name, parentId = null) { + let query = `name='${name}' and mimeType='application/vnd.google-apps.folder' and trashed=false`; + if (parentId) { + query += ` and '${parentId}' in parents`; + } + + const response = await drive.files.list({ + q: query, + fields: 'files(id, name)', + spaces: 'drive', + }); + + return response.data.files[0] || null; +} + +async function createFolder(drive, name, parentId = null) { + const fileMetadata = { + name, + mimeType: 'application/vnd.google-apps.folder', + }; + + if (parentId) { + fileMetadata.parents = [parentId]; + } + + const response = await drive.files.create({ + requestBody: fileMetadata, + fields: 'id, name', + }); + + return response.data; +} + +async function ensureGeoffreyFolders(account, subfolder = null) { + const auth = await getAuthClient(account); + const drive = google.drive({ version: 'v3', auth }); + + // Find or create main Geoffrey folder + let geoffreyFolder = await findFolder(drive, GEOFFREY_FOLDER); + if (!geoffreyFolder) { + geoffreyFolder = await createFolder(drive, GEOFFREY_FOLDER); + } + + const result = { + success: true, + account, + folders: { + Geoffrey: geoffreyFolder.id, + }, + metadata: { + timestamp: new Date().toISOString(), + } + }; + + // If specific subfolder requested, ensure it exists + if (subfolder) { + let subfolderObj = await findFolder(drive, subfolder, geoffreyFolder.id); + if (!subfolderObj) { + subfolderObj = await createFolder(drive, subfolder, geoffreyFolder.id); + } + result.folders[subfolder] = subfolderObj.id; + result.targetFolder = subfolderObj.id; + } else { + result.targetFolder = geoffreyFolder.id; + } + + return result; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + const account = args[0]; + const subfolder = args[1]; + + if (!account) { + console.error(JSON.stringify({ + error: 'Missing account', + usage: 'bun folder_manager.js <account> [subfolder]', + subfolders: SUBFOLDERS, + })); + process.exit(1); + } + + try { + const result = await ensureGeoffreyFolders(account, subfolder); + console.log(JSON.stringify(result, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + account, + })); + process.exit(1); + } +} + +if (require.main === module) { + main(); +} + +module.exports = { ensureGeoffreyFolders, findFolder, createFolder }; diff --git a/skills/google-workspace/utils/markdown_to_docs.js b/skills/google-workspace/utils/markdown_to_docs.js new file mode 100644 index 0000000..f6832b5 --- /dev/null +++ b/skills/google-workspace/utils/markdown_to_docs.js @@ -0,0 +1,256 @@ +#!/usr/bin/env node + +/** + * Markdown to Google Docs Converter + * + * Converts markdown text to Google Docs API requests for proper formatting. + * + * Supports: + * - Headers (# ## ###) + * - Bold (**text**) + * - Links [text](url) + * - Bullet lists (- item) + * - Numbered lists (1. item) + * - Horizontal rules (---) + */ + +/** + * Process inline formatting (bold, links) and return plain text + formatting requests + */ +function processInlineFormatting(text, startIndex) { + const requests = []; + let plainText = ''; + let charIndex = startIndex; + let remaining = text; + + while (remaining.length > 0) { + // Check for bold + const boldMatch = remaining.match(/^\*\*(.+?)\*\*/); + if (boldMatch) { + const boldText = boldMatch[1]; + plainText += boldText; + requests.push({ + updateTextStyle: { + range: { + startIndex: charIndex, + endIndex: charIndex + boldText.length, + }, + textStyle: { + bold: true, + }, + fields: 'bold', + }, + }); + charIndex += boldText.length; + remaining = remaining.substring(boldMatch[0].length); + continue; + } + + // Check for links + const linkMatch = remaining.match(/^\[([^\]]+)\]\(([^)]+)\)/); + if (linkMatch) { + const linkText = linkMatch[1]; + const linkUrl = linkMatch[2]; + plainText += linkText; + requests.push({ + updateTextStyle: { + range: { + startIndex: charIndex, + endIndex: charIndex + linkText.length, + }, + textStyle: { + link: { + url: linkUrl, + }, + }, + fields: 'link', + }, + }); + charIndex += linkText.length; + remaining = remaining.substring(linkMatch[0].length); + continue; + } + + // Regular character + plainText += remaining[0]; + charIndex++; + remaining = remaining.substring(1); + } + + return { plainText, requests, endIndex: charIndex }; +} + +/** + * Parse markdown and return plain text + formatting requests + * @param {string} markdown - The markdown text + * @returns {Object} { text: string, requests: Array } + */ +function parseMarkdown(markdown) { + const requests = []; + let plainText = ''; + let currentIndex = 1; // Google Docs starts at index 1 + + const lines = markdown.split('\n'); + + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + + // Horizontal rule + if (line.match(/^---+$/)) { + const ruleLine = '─'.repeat(50) + '\n'; + plainText += ruleLine; + currentIndex += ruleLine.length; + continue; + } + + // Headers + const headerMatch = line.match(/^(#{1,6})\s+(.+)$/); + if (headerMatch) { + const level = headerMatch[1].length; + const headerContent = headerMatch[2]; + + // Process inline formatting in header + const { plainText: processedText, requests: inlineRequests } = + processInlineFormatting(headerContent, currentIndex); + + const fullLine = processedText + '\n'; + + const headingStyle = level === 1 ? 'HEADING_1' : + level === 2 ? 'HEADING_2' : + level === 3 ? 'HEADING_3' : + level === 4 ? 'HEADING_4' : + level === 5 ? 'HEADING_5' : 'HEADING_6'; + + requests.push({ + updateParagraphStyle: { + range: { + startIndex: currentIndex, + endIndex: currentIndex + fullLine.length, + }, + paragraphStyle: { + namedStyleType: headingStyle, + }, + fields: 'namedStyleType', + }, + }); + + requests.push(...inlineRequests); + plainText += fullLine; + currentIndex += fullLine.length; + continue; + } + + // Bullet lists - process inline formatting within + const bulletMatch = line.match(/^[-*]\s+(.+)$/); + if (bulletMatch) { + const bulletContent = bulletMatch[1]; + const { plainText: processedText, requests: inlineRequests } = + processInlineFormatting(bulletContent, currentIndex + 2); // +2 for "• " + + const fullLine = '• ' + processedText + '\n'; + plainText += fullLine; + requests.push(...inlineRequests); + currentIndex += fullLine.length; + continue; + } + + // Numbered lists - process inline formatting within + const numberedMatch = line.match(/^(\d+)\.\s+(.+)$/); + if (numberedMatch) { + const num = numberedMatch[1]; + const listContent = numberedMatch[2]; + const prefix = num + '. '; + const { plainText: processedText, requests: inlineRequests } = + processInlineFormatting(listContent, currentIndex + prefix.length); + + const fullLine = prefix + processedText + '\n'; + plainText += fullLine; + requests.push(...inlineRequests); + currentIndex += fullLine.length; + continue; + } + + // Regular line - process inline formatting + const { plainText: processedText, requests: inlineRequests } = + processInlineFormatting(line, currentIndex); + + const fullLine = processedText + '\n'; + plainText += fullLine; + requests.push(...inlineRequests); + currentIndex += fullLine.length; + } + + return { text: plainText, requests }; +} + +/** + * Create a formatted Google Doc from markdown + * @param {Object} docs - Google Docs API instance + * @param {string} documentId - Document ID + * @param {string} markdown - Markdown content + */ +async function insertFormattedContent(docs, documentId, markdown) { + const { text, requests } = parseMarkdown(markdown); + + // First, insert the plain text + await docs.documents.batchUpdate({ + documentId, + requestBody: { + requests: [{ + insertText: { + location: { index: 1 }, + text, + }, + }], + }, + }); + + // Then apply formatting if there are any requests + if (requests.length > 0) { + await docs.documents.batchUpdate({ + documentId, + requestBody: { requests }, + }); + } + + return { textLength: text.length, formattingRequests: requests.length }; +} + +// CLI test +async function main() { + const testMarkdown = `# Main Title + +## Section One + +This is **bold text** and this is a [link](https://example.com). + +- First bullet with [a link](https://test.com) +- Second bullet with **bold** +- Third bullet + +### Subsection + +1. Numbered item with [link](https://one.com) +2. Numbered item two + +--- + +## Sources + +- [Source One](https://source1.com) +- [Source Two](https://source2.com) +`; + + const result = parseMarkdown(testMarkdown); + console.log('Plain text:'); + console.log(result.text); + console.log('\nFormatting requests:', result.requests.length); + console.log('\nSample requests:'); + result.requests.slice(0, 3).forEach(r => console.log(JSON.stringify(r, null, 2))); +} + +if (require.main === module) { + main(); +} + +module.exports = { parseMarkdown, insertFormattedContent }; diff --git a/skills/image-gen/SKILL.md b/skills/image-gen/SKILL.md new file mode 100644 index 0000000..f3e11d4 --- /dev/null +++ b/skills/image-gen/SKILL.md @@ -0,0 +1,153 @@ +--- +name: image-gen +description: Generate images using Google's Nano Banana Pro (Gemini 3 Pro Image) with workflow-based prompting +triggers: + - "create image" + - "generate image" + - "make infographic" + - "create infographic" + - "generate diagram" + - "make diagram" + - "design visual" + - "create visual" +allowed-tools: Read, Write, Bash +version: 0.1.0 +--- + +# Image Generation Skill + +Generate professional images, infographics, and diagrams using Google's Nano Banana Pro model (gemini-3-pro-image-preview). + +## Model Capabilities + +**Nano Banana Pro** (released November 20, 2025): +- **Text rendering** - Accurate, legible text in images +- **Google Search grounding** - Real-time data (weather, stocks, etc.) +- **Multi-turn conversation** - Iterative refinement +- **Up to 14 reference images** - For composition and style transfer +- **Resolutions**: 1K, 2K, 4K +- **Aspect ratios**: 1:1, 2:3, 3:2, 4:3, 16:9, 21:9 + +## Scripts + +All scripts use Python via `uv run` with inline dependencies. + +### generate.py - Text to Image +```bash +uv run scripts/generate.py "prompt" output.png [aspect_ratio] [size] +``` + +**Examples:** +```bash +# Basic image +uv run scripts/generate.py "A cozy coffee shop in autumn" coffee.png + +# Infographic with specific aspect ratio +uv run scripts/generate.py "Infographic explaining how neural networks work" nn.png 16:9 2K + +# 4K professional image +uv run scripts/generate.py "Professional headshot, studio lighting" headshot.png 3:2 4K +``` + +### edit.py - Image Editing +```bash +uv run scripts/edit.py input.png "edit instructions" output.png +``` + +**Examples:** +```bash +# Edit existing image +uv run scripts/edit.py photo.png "Change the background to a beach sunset" edited.png +``` + +### compose.py - Multi-Image Composition +```bash +uv run scripts/compose.py "prompt" output.png --refs image1.png image2.png +``` + +**Examples:** +```bash +# Combine styles from multiple images +uv run scripts/compose.py "Combine these styles into a logo" logo.png --refs style1.png style2.png +``` + +## Workflows + +Workflows provide structured approaches for specific visual types. Each workflow follows the PAI 6-step editorial process: + +1. **Extract narrative** - Understand the complete story/concept +2. **Derive visual concept** - Single metaphor with 2-3 physical objects +3. **Apply aesthetic** - Define style, colors, mood +4. **Construct prompt** - Build detailed generation instructions +5. **Generate** - Execute via script +6. **Validate** - Check against criteria, regenerate if needed + +### Available Workflows + +- **infographic.md** - Data visualization, statistics, explainers +- **diagram.md** - Technical diagrams, flowcharts, architecture + +## Workflow Usage + +When generating images, follow the appropriate workflow: + +### For Infographics +```markdown +1. What data/concept needs visualization? +2. What's the key insight or takeaway? +3. Aspect ratio: 16:9 (landscape) recommended +4. Include: clear hierarchy, minimal text, supporting icons +5. Generate at 2K minimum for text clarity +``` + +### For Diagrams +```markdown +1. What system/process is being illustrated? +2. What are the key components and relationships? +3. Style: flat colors, clean lines, minimal detail +4. Generate at 2K for label clarity +``` + +## Environment Setup + +Requires `GEMINI_API_KEY` environment variable. This should be set from Geoffrey's secrets: + +```bash +source ~/Library/Mobile\ Documents/com~apple~CloudDocs/Geoffrey/secrets/.env +``` + +## Best Practices + +### Infographics +- Use simple, direct prompts: "Infographic explaining how X works" +- Model auto-includes relevant icons/logos +- 16:9 aspect ratio works best +- Generate at 2K+ for readable text + +### General +- Multi-turn refinement: generate, then ask for specific changes +- Reference images improve consistency +- Be specific about style, mood, lighting +- SynthID watermark is automatic (Google provenance) + +## Output Location + +By default, save images to `/tmp/` or user-specified paths. For persistent storage, use: +``` +~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/images/ +``` + +## Limitations + +- No photorealistic humans (safety filter) +- No copyrighted characters +- Maximum 14 reference images for composition +- 4K only available with Nano Banana Pro + +## Pricing + +| Size | Cost per Image | +|------|---------------| +| 1K | Free tier / $0.04 | +| 2K | $0.134 | +| 4K | $0.24 | diff --git a/skills/image-gen/scripts/compose.py b/skills/image-gen/scripts/compose.py new file mode 100644 index 0000000..494fe4a --- /dev/null +++ b/skills/image-gen/scripts/compose.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 +# /// script +# dependencies = ["google-genai", "pillow", "python-dotenv"] +# /// +""" +Compose images using multiple reference images with Google's Nano Banana Pro. + +Usage: + uv run compose.py "prompt" output.png --refs image1.png image2.png [...] + +Arguments: + prompt - Text description of desired composition + output - Output file path (PNG) + --refs - Flag followed by 1-14 reference images + +Examples: + uv run compose.py "Combine these styles into a cohesive logo" logo.png --refs style1.png style2.png + uv run compose.py "Create a collage with these photos" collage.png --refs photo1.png photo2.png photo3.png +""" + +import sys +import os +import json +from pathlib import Path + +from dotenv import load_dotenv +from google import genai +from google.genai.types import GenerateContentConfig, Part +from PIL import Image + +# Load API key from Geoffrey secrets +SECRETS_PATH = Path.home() / "Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env" +if SECRETS_PATH.exists(): + load_dotenv(SECRETS_PATH) + + +def main(): + if len(sys.argv) < 4 or "--refs" not in sys.argv: + print("Usage: uv run compose.py \"prompt\" output.png --refs image1.png image2.png [...]") + print("\nSupports up to 14 reference images.") + sys.exit(1) + + prompt = sys.argv[1] + output_path = sys.argv[2] + + # Parse reference images after --refs flag + refs_index = sys.argv.index("--refs") + ref_paths = sys.argv[refs_index + 1:] + + if not ref_paths: + print("Error: No reference images provided after --refs") + sys.exit(1) + + if len(ref_paths) > 14: + print(f"Error: Maximum 14 reference images supported, got {len(ref_paths)}") + sys.exit(1) + + # Validate all reference images exist + for path in ref_paths: + if not os.path.exists(path): + print(f"Error: Reference image not found: {path}") + sys.exit(1) + + # Initialize client + api_key = os.environ.get("GEMINI_API_KEY") + if not api_key: + print("Error: GEMINI_API_KEY environment variable not set") + sys.exit(1) + + client = genai.Client(api_key=api_key) + + # Load reference images + print(f"Loading {len(ref_paths)} reference images...") + ref_images = [] + for path in ref_paths: + img = Image.open(path) + ref_images.append(img) + print(f" Loaded: {path}") + + # Configure generation + config = GenerateContentConfig( + response_modalities=["TEXT", "IMAGE"] + ) + + print(f"\nComposing image...") + print(f" Prompt: {prompt[:100]}{'...' if len(prompt) > 100 else ''}") + + try: + # Build content with all reference images and prompt + content_parts = [] + for img in ref_images: + content_parts.append(Part.from_image(img)) + content_parts.append(prompt) + + response = client.models.generate_content( + model="gemini-3-pro-image-preview", + contents=content_parts, + config=config + ) + + # Extract and save composed image + saved = False + text_response = "" + + for part in response.candidates[0].content.parts: + if hasattr(part, 'inline_data') and part.inline_data: + image = part.as_image() + + output_file = Path(output_path) + output_file.parent.mkdir(parents=True, exist_ok=True) + + image.save(output_path) + saved = True + print(f"\nComposed image saved: {output_path}") + elif hasattr(part, 'text') and part.text: + text_response = part.text + + if text_response: + print(f"\nModel response: {text_response}") + + if not saved: + print("\nError: No composed image was generated") + sys.exit(1) + + result = { + "success": True, + "output": output_path, + "reference_count": len(ref_paths), + "text_response": text_response + } + print(f"\n{json.dumps(result)}") + + except Exception as e: + print(f"\nError composing image: {e}") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/skills/image-gen/scripts/edit.py b/skills/image-gen/scripts/edit.py new file mode 100644 index 0000000..238a94b --- /dev/null +++ b/skills/image-gen/scripts/edit.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +# /// script +# dependencies = ["google-genai", "pillow", "python-dotenv"] +# /// +""" +Edit existing images using Google's Nano Banana Pro. + +Usage: + uv run edit.py input.png "edit instructions" output.png + +Arguments: + input - Input image file path + instructions - Text description of edits to make + output - Output file path (PNG) + +Examples: + uv run edit.py photo.png "Change background to sunset" edited.png + uv run edit.py logo.png "Make the text larger and blue" logo_v2.png +""" + +import sys +import os +import json +from pathlib import Path + +from dotenv import load_dotenv +from google import genai +from google.genai.types import GenerateContentConfig, Part +from PIL import Image + +# Load API key from Geoffrey secrets +SECRETS_PATH = Path.home() / "Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env" +if SECRETS_PATH.exists(): + load_dotenv(SECRETS_PATH) + + +def main(): + if len(sys.argv) < 4: + print("Usage: uv run edit.py input.png \"edit instructions\" output.png") + sys.exit(1) + + input_path = sys.argv[1] + instructions = sys.argv[2] + output_path = sys.argv[3] + + # Validate input exists + if not os.path.exists(input_path): + print(f"Error: Input file not found: {input_path}") + sys.exit(1) + + # Initialize client + api_key = os.environ.get("GEMINI_API_KEY") + if not api_key: + print("Error: GEMINI_API_KEY environment variable not set") + sys.exit(1) + + client = genai.Client(api_key=api_key) + + # Load input image + print(f"Loading input image: {input_path}") + input_image = Image.open(input_path) + + # Configure generation + config = GenerateContentConfig( + response_modalities=["TEXT", "IMAGE"] + ) + + print(f"Editing image...") + print(f" Instructions: {instructions[:100]}{'...' if len(instructions) > 100 else ''}") + + try: + # Create content with image and instructions + response = client.models.generate_content( + model="gemini-3-pro-image-preview", + contents=[ + Part.from_image(input_image), + f"Edit this image: {instructions}" + ], + config=config + ) + + # Extract and save edited image + saved = False + text_response = "" + + for part in response.candidates[0].content.parts: + if hasattr(part, 'inline_data') and part.inline_data: + image = part.as_image() + + output_file = Path(output_path) + output_file.parent.mkdir(parents=True, exist_ok=True) + + image.save(output_path) + saved = True + print(f"\nEdited image saved: {output_path}") + elif hasattr(part, 'text') and part.text: + text_response = part.text + + if text_response: + print(f"\nModel response: {text_response}") + + if not saved: + print("\nError: No edited image was generated") + sys.exit(1) + + result = { + "success": True, + "input": input_path, + "output": output_path, + "text_response": text_response + } + print(f"\n{json.dumps(result)}") + + except Exception as e: + print(f"\nError editing image: {e}") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/skills/image-gen/scripts/generate.py b/skills/image-gen/scripts/generate.py new file mode 100644 index 0000000..1acdd8c --- /dev/null +++ b/skills/image-gen/scripts/generate.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +# /// script +# dependencies = ["google-genai", "pillow", "python-dotenv"] +# /// +""" +Generate images using Google's Nano Banana Pro (Gemini 3 Pro Image). + +Usage: + uv run generate.py "prompt" output.png [aspect_ratio] [size] + +Arguments: + prompt - Text description of the image to generate + output - Output file path (PNG) + aspect_ratio - Optional: 1:1, 2:3, 3:2, 4:3, 16:9, 21:9 (default: 1:1) + size - Optional: 1K, 2K, 4K (default: 2K) + +Examples: + uv run generate.py "A cozy coffee shop" coffee.png + uv run generate.py "Infographic about AI" ai.png 16:9 2K +""" + +import sys +import os +import json +from pathlib import Path + +from dotenv import load_dotenv +from google import genai +from google.genai.types import GenerateContentConfig + +# Load API key from Geoffrey secrets +SECRETS_PATH = Path.home() / "Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env" +if SECRETS_PATH.exists(): + load_dotenv(SECRETS_PATH) + + +def main(): + if len(sys.argv) < 3: + print("Usage: uv run generate.py \"prompt\" output.png [aspect_ratio] [size]") + print("\nAspect ratios: 1:1, 2:3, 3:2, 4:3, 16:9, 21:9") + print("Sizes: 1K, 2K, 4K") + sys.exit(1) + + prompt = sys.argv[1] + output_path = sys.argv[2] + aspect_ratio = sys.argv[3] if len(sys.argv) > 3 else "1:1" + image_size = sys.argv[4] if len(sys.argv) > 4 else "2K" + + # Validate aspect ratio + valid_ratios = ["1:1", "2:3", "3:2", "4:3", "16:9", "21:9"] + if aspect_ratio not in valid_ratios: + print(f"Invalid aspect ratio: {aspect_ratio}") + print(f"Valid options: {', '.join(valid_ratios)}") + sys.exit(1) + + # Validate size + valid_sizes = ["1K", "2K", "4K"] + if image_size not in valid_sizes: + print(f"Invalid size: {image_size}") + print(f"Valid options: {', '.join(valid_sizes)}") + sys.exit(1) + + # Initialize client (uses GEMINI_API_KEY env var) + api_key = os.environ.get("GEMINI_API_KEY") + if not api_key: + print("Error: GEMINI_API_KEY environment variable not set") + sys.exit(1) + + client = genai.Client(api_key=api_key) + + # Configure generation + config = GenerateContentConfig( + response_modalities=["TEXT", "IMAGE"], + image_config={ + "aspect_ratio": aspect_ratio, + "image_size": image_size + } + ) + + print(f"Generating image...") + print(f" Prompt: {prompt[:100]}{'...' if len(prompt) > 100 else ''}") + print(f" Aspect ratio: {aspect_ratio}") + print(f" Size: {image_size}") + + try: + response = client.models.generate_content( + model="gemini-3-pro-image-preview", + contents=[prompt], + config=config + ) + + # Extract and save image + saved = False + text_response = "" + + for part in response.candidates[0].content.parts: + if hasattr(part, 'inline_data') and part.inline_data: + # Save image + image = part.as_image() + + # Ensure output directory exists + output_file = Path(output_path) + output_file.parent.mkdir(parents=True, exist_ok=True) + + image.save(output_path) + saved = True + print(f"\nImage saved: {output_path}") + elif hasattr(part, 'text') and part.text: + text_response = part.text + + if text_response: + print(f"\nModel response: {text_response}") + + if not saved: + print("\nError: No image was generated") + print("The model may have declined due to content policy.") + sys.exit(1) + + # Output JSON for programmatic use + result = { + "success": True, + "output": output_path, + "aspect_ratio": aspect_ratio, + "size": image_size, + "text_response": text_response + } + print(f"\n{json.dumps(result)}") + + except Exception as e: + print(f"\nError generating image: {e}") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/skills/image-gen/workflows/diagram.md b/skills/image-gen/workflows/diagram.md new file mode 100644 index 0000000..b243ce9 --- /dev/null +++ b/skills/image-gen/workflows/diagram.md @@ -0,0 +1,214 @@ +# Diagram Workflow + +Create technical diagrams, flowcharts, architecture diagrams, and process visualizations. + +## When to Use + +- System architecture documentation +- Process flows and workflows +- Technical explanations +- Decision trees +- Network topologies +- Component relationships + +## 6-Step Process + +### Step 1: Extract Narrative + +**Goal:** Understand the system or process being illustrated. + +Questions to answer: +- What system/process is being shown? +- What are the key components? +- What are the relationships between components? +- What is the flow direction (if any)? +- What level of detail is needed? + +**Output:** Component list and relationship description. + +### Step 2: Derive Visual Concept + +**Goal:** Choose the right diagram type. + +**Diagram types:** +| Type | Use When | +|------|----------| +| Flowchart | Sequential processes with decisions | +| Architecture | System components and connections | +| Sequence | Time-ordered interactions | +| Network | Interconnected nodes | +| Hierarchy | Parent-child relationships | +| Venn | Overlapping categories | + +**Output:** Diagram type and layout direction. + +### Step 3: Apply Aesthetic + +**Goal:** Define visual style for clarity. + +Recommended for diagrams: +- **Colors:** Limited palette (3-5 colors max) +- **Style:** Flat, clean, no gradients +- **Lines:** Consistent weight, clear arrows +- **Shapes:** Simple geometric (rectangles, circles) +- **Labels:** Sans-serif, high contrast + +**Color coding conventions:** +- Blue: Primary components +- Green: Success/positive flow +- Red: Error/warning +- Orange: External systems +- Gray: Supporting elements + +**Output:** Color scheme and style notes. + +### Step 4: Construct Prompt + +**Goal:** Build the generation prompt. + +**Template:** +``` +Create a [diagram type] showing [system/process]. + +Components: +- [Component 1]: [description] +- [Component 2]: [description] +- [Component 3]: [description] + +Relationships: +- [Component 1] connects to [Component 2] via [connection type] +- [Component 2] sends data to [Component 3] + +Layout: [direction - left-to-right, top-to-bottom, etc.] + +Style: [aesthetic from Step 3] + +Labels to include: +- [Label 1] +- [Label 2] +``` + +**Output:** Complete prompt. + +### Step 5: Generate + +**Command:** +```bash +uv run scripts/generate.py "[prompt]" output.png [aspect_ratio] 2K +``` + +**Aspect ratio by diagram type:** +- Flowcharts: 3:2 or 16:9 (horizontal flow) +- Architecture: 4:3 or 1:1 (balanced) +- Sequence: 2:3 (vertical flow) +- Network: 1:1 (balanced) + +**Settings:** +- Size: **2K minimum** for label clarity +- Model: gemini-3-pro-image-preview + +### Step 6: Validate + +**Validation criteria:** + +| Criterion | Check | +|-----------|-------| +| Completeness | All components present | +| Accuracy | Relationships correctly shown | +| Readability | All labels legible | +| Flow clarity | Direction is obvious | +| Consistency | Shapes/colors used consistently | +| Simplicity | No unnecessary elements | + +**If validation fails:** +- Identify missing or incorrect elements +- Adjust prompt +- Regenerate (max 3 iterations) + +## Example Workflow + +**Request:** Create a diagram showing a CI/CD pipeline. + +### Step 1: Extract Narrative +"CI/CD pipeline with: code commit, build, test, deploy to staging, deploy to production. Shows automated flow with manual approval gates." + +Components: +- Git repository +- Build server +- Test suite +- Staging environment +- Production environment +- Approval gates + +### Step 2: Visual Concept +Flowchart, left-to-right horizontal flow. Linear pipeline with branching for approval. + +### Step 3: Aesthetic +- Blue: Pipeline stages +- Green: Success indicators +- Orange: Approval gates +- Gray: Arrows/connectors +- Style: Flat rectangles with rounded corners, clear directional arrows + +### Step 4: Prompt +``` +Create a flowchart showing a CI/CD pipeline. + +Components: +- Git Repository: Code source +- Build Server: Compiles code +- Test Suite: Runs automated tests +- Staging: Pre-production environment +- Production: Live environment +- Approval Gate: Manual review step + +Flow: +- Git Repository -> Build Server -> Test Suite -> Staging -> Approval Gate -> Production + +Layout: Horizontal left-to-right flow + +Style: Flat design with rounded rectangles. Blue for pipeline stages, green checkmarks for success, orange for approval gate, gray arrows between stages. + +Labels: "Code", "Build", "Test", "Stage", "Approve", "Deploy" +``` + +### Step 5: Generate +```bash +uv run scripts/generate.py "Create a flowchart showing a CI/CD pipeline..." cicd.png 16:9 2K +``` + +### Step 6: Validate +- All 6 stages present +- Flow direction clear +- Labels readable +- Approval gate distinguished + +## Tips for Better Results + +1. **Keep it simple** - Fewer components = clearer diagram +2. **Be explicit about connections** - State what connects to what +3. **Specify layout direction** - Avoid ambiguous layouts +4. **Use consistent terminology** - Same names throughout prompt +5. **Include all labels** - List exact text for each component + +## Common Issues + +| Issue | Solution | +|-------|----------| +| Missing components | List every component explicitly | +| Unclear flow | State direction and connections | +| Overlapping elements | Reduce components or use larger aspect ratio | +| Inconsistent styling | Be more explicit about shapes/colors | +| Wrong diagram type | Reconsider which type fits best | + +## Alternative: Mermaid Diagrams + +For simple diagrams, consider generating Mermaid code instead: +- More precise control +- Version-controllable +- Easily editable + +Use image generation for: +- Visual appeal matters +- Marketing/presentation use +- Complex custom styling diff --git a/skills/image-gen/workflows/infographic.md b/skills/image-gen/workflows/infographic.md new file mode 100644 index 0000000..fe4c43d --- /dev/null +++ b/skills/image-gen/workflows/infographic.md @@ -0,0 +1,176 @@ +# Infographic Workflow + +Create data visualizations, explainers, and statistical infographics using the 6-step editorial process. + +## When to Use + +- Explaining concepts or processes +- Visualizing data or statistics +- Creating how-to guides +- Summarizing reports or research +- Making comparisons + +## 6-Step Process + +### Step 1: Extract Narrative + +**Goal:** Understand the complete story being told. + +Questions to answer: +- What is the main concept or data being explained? +- What is the key insight or takeaway? +- Who is the target audience? +- What action should viewers take? + +**Output:** 2-3 sentence summary of the narrative. + +### Step 2: Derive Visual Concept + +**Goal:** Translate narrative into a single visual metaphor. + +Guidelines: +- Choose 2-3 physical objects that represent the concept +- Prefer familiar, universal metaphors +- Avoid abstract shapes without meaning +- Consider spatial relationships (hierarchy, flow, comparison) + +**Examples:** +- Data growth → Plant/tree growing +- Security → Shield/lock +- Process → Pipeline/conveyor belt +- Comparison → Balance scale + +**Output:** Visual metaphor description. + +### Step 3: Apply Aesthetic + +**Goal:** Define the visual style. + +Recommended for infographics: +- **Colors:** Muted palette with 1-2 accent colors +- **Style:** Flat design, clean lines +- **Typography:** Sans-serif, clear hierarchy +- **Layout:** Clear sections, visual flow +- **Icons:** Simple, consistent style + +**Output:** Style description (2-3 sentences). + +### Step 4: Construct Prompt + +**Goal:** Build the generation prompt. + +**Template:** +``` +Create an infographic explaining [topic]. + +Visual concept: [metaphor from Step 2] + +Key elements: +- [Main data point or concept] +- [Supporting element 1] +- [Supporting element 2] + +Style: [aesthetic from Step 3] + +Layout: [horizontal/vertical], [sections description] + +Text to include: +- Title: "[title]" +- Key stat: "[number or fact]" +- [Other text elements] +``` + +**Output:** Complete prompt. + +### Step 5: Generate + +**Command:** +```bash +uv run scripts/generate.py "[prompt]" output.png 16:9 2K +``` + +**Settings for infographics:** +- Aspect ratio: **16:9** (landscape) - best for infographics +- Size: **2K minimum** - ensures text readability +- Model: gemini-3-pro-image-preview (Nano Banana Pro) + +### Step 6: Validate + +**Validation criteria:** + +| Criterion | Check | +|-----------|-------| +| Text legibility | All text is readable at 100% zoom | +| Data accuracy | Numbers/facts are displayed correctly | +| Visual hierarchy | Eye naturally flows through content | +| Color contrast | Sufficient contrast for accessibility | +| Completeness | All key elements are present | +| Brand alignment | Matches intended style | + +**If validation fails:** +- Identify specific issues +- Modify prompt to address them +- Regenerate +- Maximum 3 iterations + +## Example Workflow + +**Request:** Create an infographic about how neural networks learn. + +### Step 1: Extract Narrative +"Neural networks learn by adjusting connection weights through forward propagation and backpropagation. Key insight: the process is iterative and improves over time. Audience: Technical beginners." + +### Step 2: Visual Concept +"A network of interconnected nodes with signals flowing through, showing adjustment dials on connections. Like a city's road network with traffic lights being adjusted." + +### Step 3: Aesthetic +"Flat design with dark blue background, bright connection lines in cyan and orange. Minimal, clean style with clear node shapes." + +### Step 4: Prompt +``` +Create an infographic explaining how neural networks learn. + +Visual concept: Network of connected nodes with adjustment dials on connections, signals flowing through like traffic. + +Key elements: +- Input layer with data entering +- Hidden layers with connection weights +- Output layer with result +- Feedback loop showing backpropagation + +Style: Dark blue background, cyan and orange accents, flat design, clean minimalist style. + +Layout: Horizontal flow from left (input) to right (output), with backpropagation arrow below. + +Text to include: +- Title: "How Neural Networks Learn" +- Labels: "Input", "Hidden Layers", "Output", "Backpropagation" +``` + +### Step 5: Generate +```bash +uv run scripts/generate.py "Create an infographic explaining how neural networks learn..." neural_network.png 16:9 2K +``` + +### Step 6: Validate +- Text readable +- Flow is clear left-to-right +- Colors have good contrast +- All labels present + +## Tips for Better Results + +1. **Simple prompts often work best** - "Infographic explaining X" can produce excellent results +2. **Model understands context** - It will add relevant icons/imagery automatically +3. **Be specific about text** - Include exact wording for titles and labels +4. **Iterate with conversation** - Ask for specific changes after initial generation +5. **Use reference images** - For style consistency across multiple infographics + +## Common Issues + +| Issue | Solution | +|-------|----------| +| Text too small | Increase size to 4K or reduce text amount | +| Cluttered layout | Simplify to fewer elements | +| Wrong style | Be more explicit about aesthetic | +| Missing elements | List all required elements explicitly | diff --git a/skills/knowledge-manager/SKILL.md b/skills/knowledge-manager/SKILL.md new file mode 100644 index 0000000..cb69fdc --- /dev/null +++ b/skills/knowledge-manager/SKILL.md @@ -0,0 +1,255 @@ +--- +name: knowledge-manager +description: Manages user preferences and learned knowledge with confidence scoring +triggers: + - "what do you know" + - "my preferences" + - "show preferences" + - "remember that" + - "learn that" + - "forget that" + - "what have you learned" + - "check benefits" + - "credit card status" + - "expiring benefits" + - "card balances" +allowed-tools: Read, Write, Bash +version: 0.1.0 +--- + +# Knowledge Manager Skill + +You are Geoffrey's knowledge management system. Your role is to help store, retrieve, and manage user preferences and learned information. + +## Your Capabilities + +- **Store Preferences**: Save user preferences to the knowledge base +- **Retrieve Preferences**: Read and display stored preferences +- **Update Confidence**: Track how certain we are about each preference +- **Validate Data**: Ensure data is properly formatted before storage +- **Learn from Context**: Extract preferences from natural conversation + +## Knowledge Storage Location + +All knowledge is stored in: +``` +~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/knowledge/ +├── preferences.json # User preferences with confidence scores +├── memory.jsonl # Conversation history (future) +└── patterns.json # Detected patterns (future) +``` + +## Preference Structure + +Each preference includes: +- **Category**: Domain (travel, work, communication, etc.) +- **Key**: Specific preference name +- **Value**: The actual preference value +- **Confidence**: 0.0-1.0 score + - 1.0 = Explicitly stated by user + - 0.8-0.9 = Strong pattern (5+ observations) + - 0.6-0.7 = Moderate pattern (3-4 observations) + - 0.4-0.5 = Weak pattern (1-2 observations) + - <0.4 = Insufficient data +- **Learned From**: Array of sources (explicit, conversation, pattern) +- **Last Updated**: Timestamp + +## How to Store a Preference + +When the user teaches you something: + +1. **Read current preferences**: + ```bash + cat ~/Library/Mobile\ Documents/com~apple~CloudDocs/Geoffrey/knowledge/preferences.json + ``` + +2. **Parse and validate** the user's statement + +3. **Update the JSON** with new preference: + - Add to appropriate category + - Set confidence based on how it was learned + - Record the source + - Update timestamp + +4. **Write back** to the file + +5. **Confirm** to the user what was learned + +## Example Interactions + +### User teaches explicitly: +``` +User: "I always prefer Marriott hotels. I'm Platinum Elite." + +Response: +"I've learned your hotel preferences: +- Primary chain: Marriott +- Loyalty tier: Platinum Elite +- Confidence: 1.0 (explicitly stated) + +Stored in knowledge base. I'll use this for all future travel planning." +``` + +### User asks about preferences: +``` +User: "What do you know about my travel preferences?" + +Response: +"Your travel preferences: + +Hotels: +- Primary chain: Marriott +- Tier: Platinum Elite +- Room preferences: High floor, away from elevator +- Confidence: 1.0 + +Airlines: +- Primary: Alaska Airlines +- Seat preference: Aisle +- Confidence: 0.8 (observed pattern from 5 bookings) + +You can update these anytime by telling me or using /preferences" +``` + +## When to Activate + +Use this skill when: +- User explicitly teaches you something ("I prefer...", "Always...", "Never...") +- User asks about their preferences ("What do you know about...", "Show my preferences") +- User wants to update or delete knowledge +- User asks "What have you learned about me?" + +## Important Guidelines + +- **Always confirm** before storing new preferences +- **Never overwrite** high-confidence data with low-confidence data +- **Ask for clarification** if uncertain +- **Respect privacy**: Never share preferences outside this system +- **Be transparent**: Always explain what was learned and why + +## Data Validation + +Before storing, verify: +- ✅ Category is appropriate (travel, work, communication, personal) +- ✅ Value is valid for the key type +- ✅ Confidence score is 0.0-1.0 +- ✅ Timestamp is ISO-8601 format +- ✅ JSON is valid and well-formatted + +## Error Handling + +If the knowledge file doesn't exist: +- Create it with default structure +- Initialize version 1.0 +- Add first preference + +If JSON is malformed: +- Report the error to user +- Don't overwrite the file +- Ask user to check file manually + +## Credit Card Benefits Tracking + +### Overview +Track credit card balances, expiring benefits, and annual credits across multiple accounts for both Hagel and Carrie. + +### Storage Location +``` +~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/knowledge/credit-card-status.json +``` + +### Accounts to Track + +**Hagel:** +- Chase Sapphire Reserve (...2502) +- Marriott Bonvoy Amex (3 cards: ...81004, ...43001, ...61000) +- Alaska/Atmos Rewards + +**Carrie:** +- Alaska/Atmos account +- Chase account(s) + +### Data Structure +```json +{ + "last_updated": "2025-11-22T20:00:00Z", + "accounts": { + "hagel": { + "chase": { + "ultimate_rewards_points": 53254, + "cards": [{ + "name": "Sapphire Reserve", + "last_four": "2502", + "credits": { + "travel": {"total": 300, "used": 0, "resets": "anniversary"}, + "doordash": {"total": 50, "used": 0, "expires": "2025-12-31"}, + "instacart": {"total": 15, "used": 0, "expires": "2025-12-31"}, + "lyft": {"total": 0, "used": 0, "expires": "2025-12-31"} + } + }] + }, + "marriott": { + "points": 215323, + "status": "Titanium Elite", + "nights_this_year": 92, + "expiring_benefits": [ + {"name": "Free Night Award (40k)", "expires": "2025-12-31"}, + {"name": "Suite Night Award", "expires": "2025-12-31"} + ] + }, + "alaska": { + "miles": 469888, + "status": "Atmos Platinum", + "companion_fare": {"available": false, "expires": null} + } + }, + "carrie": { + "chase": {}, + "alaska": {} + } + }, + "alerts": [ + {"account": "hagel.marriott", "item": "Free Night Award", "expires": "2025-12-31", "days_remaining": 39} + ] +} +``` + +### Check Benefits Workflow + +When user triggers "check benefits": + +1. **Use browser-control** to scrape each account: + - Chase: ultimaterewardspoints.chase.com + benefits page + - Marriott: marriott.com/loyalty/myAccount/activity.mi + - Alaska: alaskaair.com/account/wallet + - Amex: global.americanexpress.com/dashboard + +2. **Extract key data**: + - Point/mile balances + - Credit usage status + - Expiring benefits with dates + - Free night certificates + +3. **Save to status file** in iCloud + +4. **Generate alerts** for items expiring within 30 days + +5. **Report to user** with action items + +### Monthly Reminder + +A recurring OmniFocus task reminds Hagel to run the benefits check monthly. Task details: +- Project: Personal +- Due: 1st of each month +- Tags: Organization +- Note: "Run 'check benefits' in Geoffrey to update credit card status" + +## Future Enhancements + +In later phases, this skill will: +- Automatically extract preferences from conversations +- Detect conflicting preferences +- Suggest preference updates based on patterns +- Track preference changes over time +- Sync with conversation memory system +- **Auto-alert on expiring benefits** via email or notification diff --git a/skills/obsidian-manager/SKILL.md b/skills/obsidian-manager/SKILL.md new file mode 100644 index 0000000..9c6366c --- /dev/null +++ b/skills/obsidian-manager/SKILL.md @@ -0,0 +1,303 @@ +--- +name: obsidian-manager +description: Manage Obsidian vault for persistent knowledge storage, search, and retrieval +triggers: + - "save to obsidian" + - "search my notes" + - "find in vault" + - "check my readwise" + - "search readwise" + - "search snipd" + - "check my highlights" + - "create note" + - "add to obsidian" + - "what did I read about" + - "what podcasts mentioned" +allowed-tools: Read, Write, Bash, Glob, Grep +version: 0.1.0 +--- + +# Obsidian Manager Skill + +Manage the user's Obsidian vault as a persistent second brain. Read existing knowledge, write new content, and search across years of highlights and notes. + +## Vault Configuration + +**Path:** `/Users/hagelk/Library/Mobile Documents/iCloud~md~obsidian/Documents/Personal_Notes/` + +**Write Mode:** Auto-create new files, confirm before updating existing files. + +## Vault Structure + +``` +Personal_Notes/ +├── Geoffrey/ # Geoffrey-generated content +│ ├── Research/ # Research task outputs +│ ├── Reports/ # Generated reports and artifacts +│ │ ├── PSD/ # Peninsula School District reports +│ │ │ ├── Discipline/ # Discipline reports and infographics +│ │ │ ├── Enrollment/ # Enrollment reports +│ │ │ └── {topic}/ # Other PSD topics +│ │ ├── HRG/ # Hat Rack Group (consulting LLC) reports +│ │ │ └── {topic}/ # HRG topics +│ │ ├── Personal/ # Personal reports +│ │ │ └── {topic}/ # Personal topics +│ │ └── {org}/ # Other organizations as needed +│ ├── Daily-Logs/ # Session summaries +│ ├── Learnings/ # Extracted patterns +│ └── Decisions/ # Major decisions with rationale +├── Meetings/ # Meeting notes (YYYY-MM-DD format) +├── People/ # Contact profiles with metadata +├── Readwise/ # Synced highlights (368 articles, 34 books) +│ ├── Articles/ +│ ├── Books/ +│ ├── Podcasts/ +│ └── Tweets/ +├── Snipd/ # Podcast highlights (58+ episodes) +│ └── Data/ # Podcast folders > episodes +└── Templates/ # Note templates +``` + +## Scripts + +All scripts use Python via `uv run` with inline dependencies. + +### Search Scripts + +#### search.py - General Vault Search +```bash +uv run scripts/search.py "query" [folder] [--limit N] +``` + +Search across the vault for keyword matches. Returns file paths and matching excerpts. + +**Examples:** +```bash +# Search entire vault +uv run scripts/search.py "prompt engineering" + +# Search specific folder +uv run scripts/search.py "leadership" People + +# Limit results +uv run scripts/search.py "AI" Readwise/Articles --limit 10 +``` + +#### search-readwise.py - Search Highlights +```bash +uv run scripts/search-readwise.py "query" [--author "name"] [--category articles|books|podcasts] +``` + +Search Readwise highlights by topic, author, or category. + +**Examples:** +```bash +# Search by topic +uv run scripts/search-readwise.py "second brain" + +# Search specific author +uv run scripts/search-readwise.py "AI" --author "Andrej Karpathy" + +# Search books only +uv run scripts/search-readwise.py "habits" --category books +``` + +#### search-snipd.py - Search Podcast Transcripts +```bash +uv run scripts/search-snipd.py "query" [--show "podcast name"] +``` + +Search Snipd podcast transcripts and snips. + +**Examples:** +```bash +# Search all podcasts +uv run scripts/search-snipd.py "machine learning" + +# Search specific show +uv run scripts/search-snipd.py "leadership" --show "Huberman Lab" +``` + +### Creation Scripts + +#### create-note.py - Create New Note +```bash +uv run scripts/create-note.py "title" "content" [--folder Geoffrey/Research] [--tags tag1,tag2] [--related "[[Note]]"] +``` + +Create a new note with proper frontmatter and optional backlinks. + +**Examples:** +```bash +# Create research note +uv run scripts/create-note.py "AI Model Comparison" "Content here..." --folder Geoffrey/Research --tags research,ai + +# Create with backlinks +uv run scripts/create-note.py "Meeting Notes" "Content..." --folder Meetings --related "[[John Smith]],[[Project Alpha]]" +``` + +#### open-in-obsidian.py - Open Note in Obsidian +```bash +uv run scripts/open-in-obsidian.py "path/to/note.md" +``` + +Opens the specified note in Obsidian using Actions URI. + +## Content Routing + +**CRITICAL:** When creating content, use these destinations. NEVER dump files directly into `Geoffrey/` - always use proper subfolders. + +| Content Type | Folder | Naming Pattern | +|--------------|--------|----------------| +| Research results | `Geoffrey/Research/` | `YYYY-MM-DD-topic.md` | +| **Reports** | `Geoffrey/Reports/{org}/{topic}/` | Descriptive name with date | +| **Images/Infographics** | Same as parent report | `Descriptive Name YYYY-MM-DD.png` | +| Meeting notes | `Meetings/` | `Topic - YYYY-MM-DD.md` | +| Daily summaries | `Geoffrey/Daily-Logs/` | `YYYY-MM-DD.md` | +| Learnings | `Geoffrey/Learnings/` | `topic-slug.md` | +| Decisions | `Geoffrey/Decisions/` | `YYYY-MM-DD-decision.md` | +| Person updates | `People/` | Existing file name | + +**Naming Rules:** +- All images/infographics MUST include date in filename +- Format: `Descriptive Name YYYY-MM-DD.png` or `Descriptive Name YYYY-MM-DD to YYYY-MM-DD.png` for date ranges +- Example: `Peninsula High School Discipline Report 2025-11-17 to 2025-11-20.png` + +**Reports Folder Structure:** +Pattern: `Geoffrey/Reports/{organization}/{topic}/` + +Organizations: +- **PSD** - Peninsula School District reports + - `Geoffrey/Reports/PSD/Discipline/` + - `Geoffrey/Reports/PSD/Enrollment/` + - `Geoffrey/Reports/PSD/Attendance/` + - `Geoffrey/Reports/PSD/{topic}/` + +- **HRG** - Hat Rack Group (consulting LLC) reports + - `Geoffrey/Reports/HRG/{topic}/` + +- **Personal** - Personal reports + - `Geoffrey/Reports/Personal/{topic}/` + +- **{org}** - Other organizations as needed + +## Frontmatter Standard + +All Geoffrey-created notes should include: + +```yaml +--- +created: 2025-11-23 +tags: [geoffrey, research] +source: geoffrey +related: + - "[[Related Note 1]]" + - "[[Related Note 2]]" +--- +``` + +## When to Read from Vault + +- **Before research tasks:** Check if user has relevant Readwise highlights or existing notes +- **When people mentioned:** Look up context in People folder +- **For meeting prep:** Find past meetings and related notes +- **For context:** Search Snipd transcripts for podcast discussions on topic + +## When to Write to Vault + +- **After research:** Save results to `Geoffrey/Research/` +- **Learned patterns:** Extract insights to `Geoffrey/Learnings/` +- **Major decisions:** Document with rationale in `Geoffrey/Decisions/` +- **Session summaries:** Optional daily logs to `Geoffrey/Daily-Logs/` + +## Creating Backlinks + +Always create backlinks to existing content: + +1. **Search before creating:** Find related notes first +2. **Use wiki-links:** `[[Note Title]]` format +3. **Add to frontmatter:** List in `related:` field +4. **Reference sources:** Link to Readwise/Snipd sources when relevant + +**Example:** +```markdown +Based on insights from [[Readwise/Articles/Building a Second Brain]], +and discussed in [[Snipd/Data/Huberman Lab/episode-123]], +the key pattern is... +``` + +## Readwise Content Format + +Readwise notes have this structure: + +```yaml +--- +Author: "Author Name" +Full Title: "Article Title" +Category: #articles +Summary: "AI-generated summary" +--- + +## Highlights +- Highlight text with optional tags like [[topic]] +``` + +## Snipd Content Format + +Snipd episodes have rich metadata: + +```yaml +--- +episode_show: "Podcast Name" +episode_publish_date: 2024-01-15 +mentioned_books: ["Book 1", "Book 2"] +snips_count: 5 +--- + +### Snip 1 +**Timestamp:** 00:15:30 +> Quote text here + +**Transcript:** Full context... +``` + +## Actions URI Integration + +Use Actions URI to interact with Obsidian app: + +```bash +# Open a note +open "obsidian://actions-uri/note/open?vault=Personal_Notes&file=Geoffrey/Research/note.md" + +# Create and open +open "obsidian://actions-uri/note/create?vault=Personal_Notes&file=path&content=..." +``` + +## Best Practices + +1. **Search before creating:** Always check for existing content +2. **Link generously:** Create connections between notes +3. **Use consistent tags:** Match existing tag patterns +4. **Keep notes atomic:** One idea per note in Learnings +5. **Include sources:** Always cite Readwise/Snipd sources +6. **Respect existing structure:** Don't reorganize user's folders + +## Output Format + +When completing Obsidian operations: + +```markdown +## Summary +What was done + +## Files +- Created: `path/to/new.md` +- Updated: `path/to/existing.md` (if confirmed) + +## Related Content Found +- [[Relevant Note 1]] - why it's relevant +- [[Relevant Note 2]] - why it's relevant + +## Next Steps +- Recommendations if any +``` diff --git a/skills/obsidian-manager/scripts/create-note.py b/skills/obsidian-manager/scripts/create-note.py new file mode 100644 index 0000000..f9f2977 --- /dev/null +++ b/skills/obsidian-manager/scripts/create-note.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 +# /// script +# dependencies = ["python-frontmatter", "pyyaml"] +# /// +""" +Create a new note in the Obsidian vault with proper frontmatter. + +Usage: + uv run create-note.py "title" "content" [--folder path] [--tags tag1,tag2] [--related "[[Note]]"] + +Arguments: + title - Note title (will be used for filename) + content - Note content (markdown) + --folder - Folder path relative to vault (default: Geoffrey/Research) + --tags - Comma-separated tags + --related - Comma-separated related notes as wiki-links + +Examples: + uv run create-note.py "AI Model Comparison" "Content..." --folder Geoffrey/Research --tags research,ai + uv run create-note.py "Meeting Notes" "Content..." --folder Meetings --related "[[John Smith]],[[Project]]" +""" + +import sys +import os +import json +import re +from pathlib import Path +from datetime import datetime +import frontmatter + +VAULT_PATH = Path.home() / "Library/Mobile Documents/iCloud~md~obsidian/Documents/Personal_Notes" + + +def slugify(title: str) -> str: + """Convert title to filename-safe slug.""" + # Replace spaces with hyphens, remove special chars + slug = re.sub(r'[^\w\s-]', '', title.lower()) + slug = re.sub(r'[-\s]+', '-', slug).strip('-') + return slug + + +def create_note( + title: str, + content: str, + folder: str = "Geoffrey/Research", + tags: list[str] = None, + related: list[str] = None +) -> str: + """Create a new note with frontmatter.""" + + # Ensure folder exists + folder_path = VAULT_PATH / folder + folder_path.mkdir(parents=True, exist_ok=True) + + # Generate filename + date_prefix = datetime.now().strftime("%Y-%m-%d") + slug = slugify(title) + filename = f"{date_prefix}-{slug}.md" + file_path = folder_path / filename + + # Check if file exists + if file_path.exists(): + # Add timestamp to make unique + timestamp = datetime.now().strftime("%H%M%S") + filename = f"{date_prefix}-{slug}-{timestamp}.md" + file_path = folder_path / filename + + # Build frontmatter + metadata = { + "created": datetime.now().strftime("%Y-%m-%d"), + "source": "geoffrey" + } + + if tags: + metadata["tags"] = ["geoffrey"] + [t.strip() for t in tags if t.strip()] + else: + metadata["tags"] = ["geoffrey"] + + if related: + metadata["related"] = [r.strip() for r in related if r.strip()] + + # Create the post + post = frontmatter.Post(content) + post.metadata = metadata + + # Add title as H1 if not already present + if not content.strip().startswith('#'): + post.content = f"# {title}\n\n{content}" + + # Write file + with open(file_path, 'w', encoding='utf-8') as f: + f.write(frontmatter.dumps(post)) + + return str(file_path.relative_to(VAULT_PATH)) + + +def main(): + if len(sys.argv) < 3: + print("Usage: uv run create-note.py \"title\" \"content\" [--folder path] [--tags t1,t2] [--related \"[[Note]]\"]") + sys.exit(1) + + title = sys.argv[1] + content = sys.argv[2] + folder = "Geoffrey/Research" + tags = [] + related = [] + + # Parse arguments + i = 3 + while i < len(sys.argv): + if sys.argv[i] == "--folder" and i + 1 < len(sys.argv): + folder = sys.argv[i + 1] + i += 2 + elif sys.argv[i] == "--tags" and i + 1 < len(sys.argv): + tags = sys.argv[i + 1].split(',') + i += 2 + elif sys.argv[i] == "--related" and i + 1 < len(sys.argv): + related = sys.argv[i + 1].split(',') + i += 2 + else: + i += 1 + + print(f"Creating note: {title}") + print(f"Folder: {folder}") + if tags: + print(f"Tags: {', '.join(tags)}") + if related: + print(f"Related: {', '.join(related)}") + + relative_path = create_note(title, content, folder, tags, related) + full_path = VAULT_PATH / relative_path + + print(f"\nNote created: {relative_path}") + + # Output JSON for programmatic use + result = { + "success": True, + "path": relative_path, + "full_path": str(full_path), + "folder": folder, + "title": title + } + print(f"\n{json.dumps(result)}") + + +if __name__ == "__main__": + main() diff --git a/skills/obsidian-manager/scripts/open-in-obsidian.py b/skills/obsidian-manager/scripts/open-in-obsidian.py new file mode 100644 index 0000000..c8c18d8 --- /dev/null +++ b/skills/obsidian-manager/scripts/open-in-obsidian.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# /// script +# dependencies = [] +# /// +""" +Open a note in Obsidian using Actions URI. + +Usage: + uv run open-in-obsidian.py "path/to/note.md" + +Arguments: + path - Path to note relative to vault root + +Examples: + uv run open-in-obsidian.py "Geoffrey/Research/2025-11-23-ai-comparison.md" + uv run open-in-obsidian.py "People/John Smith.md" +""" + +import sys +import subprocess +import urllib.parse +from pathlib import Path + +VAULT_NAME = "Personal_Notes" +VAULT_PATH = Path.home() / "Library/Mobile Documents/iCloud~md~obsidian/Documents/Personal_Notes" + + +def open_in_obsidian(note_path: str) -> bool: + """Open a note in Obsidian using Actions URI.""" + + # Remove .md extension if present (Actions URI doesn't need it) + if note_path.endswith('.md'): + note_path = note_path[:-3] + + # URL encode the path + encoded_path = urllib.parse.quote(note_path, safe='') + + # Build Actions URI + # Using actions-uri plugin: obsidian://actions-uri/note/open + uri = f"obsidian://actions-uri/note/open?vault={urllib.parse.quote(VAULT_NAME)}&file={encoded_path}" + + try: + # Open the URI (macOS) + subprocess.run(['open', uri], check=True) + return True + except subprocess.CalledProcessError as e: + print(f"Error opening note: {e}") + return False + + +def main(): + if len(sys.argv) < 2: + print("Usage: uv run open-in-obsidian.py \"path/to/note.md\"") + print("\nExamples:") + print(" uv run open-in-obsidian.py \"Geoffrey/Research/note.md\"") + print(" uv run open-in-obsidian.py \"People/John Smith.md\"") + sys.exit(1) + + note_path = sys.argv[1] + + # Verify file exists + full_path = VAULT_PATH / note_path + if not full_path.exists(): + print(f"Warning: Note does not exist at {full_path}") + print("Attempting to open anyway (Obsidian may create it)...") + + print(f"Opening in Obsidian: {note_path}") + + if open_in_obsidian(note_path): + print("Note opened successfully") + else: + print("Failed to open note") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/skills/obsidian-manager/scripts/search-readwise.py b/skills/obsidian-manager/scripts/search-readwise.py new file mode 100644 index 0000000..e66e3cc --- /dev/null +++ b/skills/obsidian-manager/scripts/search-readwise.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +# /// script +# dependencies = ["python-frontmatter", "pyyaml"] +# /// +""" +Search Readwise highlights by topic, author, or category. + +Usage: + uv run search-readwise.py "query" [--author "name"] [--category articles|books|podcasts|tweets] + +Arguments: + query - Search term or phrase + --author - Filter by author name + --category - Filter by category (articles, books, podcasts, tweets) + +Examples: + uv run search-readwise.py "second brain" + uv run search-readwise.py "AI" --author "Andrej Karpathy" + uv run search-readwise.py "habits" --category books +""" + +import sys +import os +import json +import re +from pathlib import Path +import frontmatter + +VAULT_PATH = Path.home() / "Library/Mobile Documents/iCloud~md~obsidian/Documents/Personal_Notes" +READWISE_PATH = VAULT_PATH / "Readwise" + + +def search_readwise(query: str, author: str = "", category: str = "", limit: int = 15) -> list[dict]: + """Search Readwise highlights.""" + results = [] + + # Determine search paths based on category + if category: + category_map = { + "articles": "Articles", + "books": "Books", + "podcasts": "Podcasts", + "tweets": "Tweets" + } + search_paths = [READWISE_PATH / category_map.get(category.lower(), category)] + else: + search_paths = [ + READWISE_PATH / "Articles", + READWISE_PATH / "Books", + READWISE_PATH / "Podcasts", + READWISE_PATH / "Tweets" + ] + + pattern = re.compile(re.escape(query), re.IGNORECASE) + author_pattern = re.compile(re.escape(author), re.IGNORECASE) if author else None + + for search_path in search_paths: + if not search_path.exists(): + continue + + for md_file in search_path.rglob("*.md"): + try: + post = frontmatter.load(md_file) + content = post.content + metadata = post.metadata + + # Filter by author if specified + if author_pattern: + file_author = metadata.get("Author", "") + if not author_pattern.search(file_author): + continue + + # Search in content + matches = list(pattern.finditer(content)) + if not matches: + continue + + # Extract highlights (lines starting with - or >) + highlights = [] + for line in content.split('\n'): + line = line.strip() + if (line.startswith('-') or line.startswith('>')) and pattern.search(line): + highlights.append(line[:200]) + + # Get context around first match if no highlight found + if not highlights and matches: + first_match = matches[0] + start = max(0, first_match.start() - 50) + end = min(len(content), first_match.end() + 150) + excerpt = content[start:end].strip() + excerpt = re.sub(r'\s+', ' ', excerpt) + highlights = [excerpt] + + results.append({ + "file": str(md_file.relative_to(VAULT_PATH)), + "title": metadata.get("Full Title", md_file.stem), + "author": metadata.get("Author", "Unknown"), + "category": search_path.name, + "matches": len(matches), + "highlights": highlights[:3] # Top 3 matching highlights + }) + + if len(results) >= limit: + break + + except Exception as e: + continue + + if len(results) >= limit: + break + + # Sort by number of matches + results.sort(key=lambda x: x["matches"], reverse=True) + return results[:limit] + + +def main(): + if len(sys.argv) < 2: + print("Usage: uv run search-readwise.py \"query\" [--author \"name\"] [--category type]") + sys.exit(1) + + query = sys.argv[1] + author = "" + category = "" + + # Parse arguments + i = 2 + while i < len(sys.argv): + if sys.argv[i] == "--author" and i + 1 < len(sys.argv): + author = sys.argv[i + 1] + i += 2 + elif sys.argv[i] == "--category" and i + 1 < len(sys.argv): + category = sys.argv[i + 1] + i += 2 + else: + i += 1 + + filters = [] + if author: + filters.append(f"author: {author}") + if category: + filters.append(f"category: {category}") + filter_str = f" ({', '.join(filters)})" if filters else "" + + print(f"Searching Readwise for '{query}'{filter_str}...") + results = search_readwise(query, author, category) + + if not results: + print(f"\nNo Readwise highlights found for '{query}'") + return + + print(f"\nFound {len(results)} sources:\n") + + for i, result in enumerate(results, 1): + print(f"{i}. **{result['title']}**") + print(f" Author: {result['author']} | Category: {result['category']} | {result['matches']} matches") + print(f" File: {result['file']}") + if result['highlights']: + print(f" Highlights:") + for h in result['highlights']: + print(f" - {h[:150]}{'...' if len(h) > 150 else ''}") + print() + + # Output JSON for programmatic use + print(f"\n{json.dumps({'results': results, 'total': len(results)})}") + + +if __name__ == "__main__": + main() diff --git a/skills/obsidian-manager/scripts/search-snipd.py b/skills/obsidian-manager/scripts/search-snipd.py new file mode 100644 index 0000000..6cd5621 --- /dev/null +++ b/skills/obsidian-manager/scripts/search-snipd.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 +# /// script +# dependencies = ["python-frontmatter", "pyyaml"] +# /// +""" +Search Snipd podcast transcripts and snips. + +Usage: + uv run search-snipd.py "query" [--show "podcast name"] + +Arguments: + query - Search term or phrase + --show - Filter by podcast show name + +Examples: + uv run search-snipd.py "machine learning" + uv run search-snipd.py "leadership" --show "Huberman Lab" +""" + +import sys +import os +import json +import re +from pathlib import Path +import frontmatter + +VAULT_PATH = Path.home() / "Library/Mobile Documents/iCloud~md~obsidian/Documents/Personal_Notes" +SNIPD_PATH = VAULT_PATH / "Snipd" + + +def search_snipd(query: str, show: str = "", limit: int = 15) -> list[dict]: + """Search Snipd podcast transcripts.""" + results = [] + + search_path = SNIPD_PATH / "Data" + if not search_path.exists(): + search_path = SNIPD_PATH + + pattern = re.compile(re.escape(query), re.IGNORECASE) + show_pattern = re.compile(re.escape(show), re.IGNORECASE) if show else None + + for md_file in search_path.rglob("*.md"): + try: + post = frontmatter.load(md_file) + content = post.content + metadata = post.metadata + + # Filter by show if specified + if show_pattern: + episode_show = metadata.get("episode_show", "") + if not show_pattern.search(episode_show): + continue + + # Search in content + matches = list(pattern.finditer(content)) + if not matches: + continue + + # Extract snips (look for timestamp patterns and quotes) + snips = [] + lines = content.split('\n') + for j, line in enumerate(lines): + if pattern.search(line): + # Get context (this line and surrounding) + start = max(0, j - 1) + end = min(len(lines), j + 2) + context = ' '.join(lines[start:end]).strip() + context = re.sub(r'\s+', ' ', context) + if context: + snips.append(context[:300]) + + results.append({ + "file": str(md_file.relative_to(VAULT_PATH)), + "title": metadata.get("episode_title", md_file.stem), + "show": metadata.get("episode_show", "Unknown"), + "date": str(metadata.get("episode_publish_date", "")), + "snips_count": metadata.get("snips_count", 0), + "matches": len(matches), + "excerpts": snips[:3] # Top 3 matching excerpts + }) + + if len(results) >= limit: + break + + except Exception as e: + continue + + # Sort by number of matches + results.sort(key=lambda x: x["matches"], reverse=True) + return results[:limit] + + +def main(): + if len(sys.argv) < 2: + print("Usage: uv run search-snipd.py \"query\" [--show \"podcast name\"]") + sys.exit(1) + + query = sys.argv[1] + show = "" + + # Parse arguments + i = 2 + while i < len(sys.argv): + if sys.argv[i] == "--show" and i + 1 < len(sys.argv): + show = sys.argv[i + 1] + i += 2 + else: + i += 1 + + filter_str = f" (show: {show})" if show else "" + + print(f"Searching Snipd podcasts for '{query}'{filter_str}...") + results = search_snipd(query, show) + + if not results: + print(f"\nNo Snipd episodes found for '{query}'") + return + + print(f"\nFound {len(results)} episodes:\n") + + for i, result in enumerate(results, 1): + print(f"{i}. **{result['title']}**") + print(f" Show: {result['show']} | Date: {result['date']} | Snips: {result['snips_count']} | {result['matches']} matches") + print(f" File: {result['file']}") + if result['excerpts']: + print(f" Excerpts:") + for e in result['excerpts']: + print(f" - {e[:200]}{'...' if len(e) > 200 else ''}") + print() + + # Output JSON for programmatic use + print(f"\n{json.dumps({'results': results, 'total': len(results)})}") + + +if __name__ == "__main__": + main() diff --git a/skills/obsidian-manager/scripts/search.py b/skills/obsidian-manager/scripts/search.py new file mode 100644 index 0000000..7190ed0 --- /dev/null +++ b/skills/obsidian-manager/scripts/search.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +# /// script +# dependencies = ["python-frontmatter"] +# /// +""" +Search Obsidian vault for keyword matches. + +Usage: + uv run search.py "query" [folder] [--limit N] + +Arguments: + query - Search term or phrase + folder - Optional subfolder to search (default: entire vault) + --limit - Maximum results to return (default: 20) + +Examples: + uv run search.py "prompt engineering" + uv run search.py "leadership" People + uv run search.py "AI" Readwise/Articles --limit 10 +""" + +import sys +import os +import json +import re +from pathlib import Path + +VAULT_PATH = Path.home() / "Library/Mobile Documents/iCloud~md~obsidian/Documents/Personal_Notes" + + +def search_vault(query: str, folder: str = "", limit: int = 20) -> list[dict]: + """Search vault for query matches.""" + results = [] + search_path = VAULT_PATH / folder if folder else VAULT_PATH + + if not search_path.exists(): + print(f"Error: Path does not exist: {search_path}") + sys.exit(1) + + # Case-insensitive search pattern + pattern = re.compile(re.escape(query), re.IGNORECASE) + + for md_file in search_path.rglob("*.md"): + try: + content = md_file.read_text(encoding='utf-8') + matches = list(pattern.finditer(content)) + + if matches: + # Get context around first match + first_match = matches[0] + start = max(0, first_match.start() - 100) + end = min(len(content), first_match.end() + 100) + excerpt = content[start:end].strip() + + # Clean up excerpt + excerpt = re.sub(r'\s+', ' ', excerpt) + if start > 0: + excerpt = "..." + excerpt + if end < len(content): + excerpt = excerpt + "..." + + results.append({ + "file": str(md_file.relative_to(VAULT_PATH)), + "matches": len(matches), + "excerpt": excerpt + }) + + if len(results) >= limit: + break + + except Exception as e: + continue # Skip files that can't be read + + # Sort by number of matches + results.sort(key=lambda x: x["matches"], reverse=True) + return results[:limit] + + +def main(): + if len(sys.argv) < 2: + print("Usage: uv run search.py \"query\" [folder] [--limit N]") + sys.exit(1) + + query = sys.argv[1] + folder = "" + limit = 20 + + # Parse arguments + i = 2 + while i < len(sys.argv): + if sys.argv[i] == "--limit" and i + 1 < len(sys.argv): + limit = int(sys.argv[i + 1]) + i += 2 + else: + folder = sys.argv[i] + i += 1 + + print(f"Searching for '{query}' in {folder or 'entire vault'}...") + results = search_vault(query, folder, limit) + + if not results: + print(f"\nNo results found for '{query}'") + return + + print(f"\nFound {len(results)} results:\n") + + for i, result in enumerate(results, 1): + print(f"{i}. **{result['file']}** ({result['matches']} matches)") + print(f" {result['excerpt']}\n") + + # Output JSON for programmatic use + print(f"\n{json.dumps({'results': results, 'total': len(results)})}") + + +if __name__ == "__main__": + main() diff --git a/skills/omnifocus-manager/SKILL.md b/skills/omnifocus-manager/SKILL.md new file mode 100644 index 0000000..0910de7 --- /dev/null +++ b/skills/omnifocus-manager/SKILL.md @@ -0,0 +1,324 @@ +--- +name: omnifocus-manager +description: Manage OmniFocus tasks, projects, and inbox with proper tagging and organization +triggers: + - "add task" + - "create task" + - "new task" + - "follow up with" + - "triage omnifocus" + - "triage my omnifocus" + - "omnifocus inbox" + - "clean up omnifocus" + - "check omnifocus" + - "show tasks" + - "what's due" + - "omnifocus review" +allowed-tools: Read, Bash +version: 0.1.0 +--- + +# OmniFocus Manager Skill + +Manage OmniFocus tasks with proper project assignment, tagging, and organization based on user preferences. + +## When to Activate + +Use this skill when user wants to: +- Add/create tasks +- Follow up with someone +- Triage or review inbox +- Clean up or organize tasks +- Check what's due or available +- Query task status + +## User Preferences + +**Task Creation Philosophy:** +- Always assign to a project (never leave in Inbox) +- Always set expected completion date +- Tag with person + "Follow Up" for 1:1 discussions +- Use location tags for shopping tasks + +## Available Scripts + +Scripts are in `./scripts/` directory. Run via: +```bash +osascript -l JavaScript ./scripts/script-name.js +``` + +**IMPORTANT:** Always use pure JXA, NOT Omni Automation URL scheme. The URL scheme triggers security popups for every unique script. JXA runs silently. + +Key JXA patterns: +- `doc.inboxTasks.push(task)` - create new tasks +- `app.add(tag, {to: task.tags})` - add existing tags (not push!) +- `task.assignedContainer = project` - move to project + +### get_inbox.js +Returns remaining inbox tasks (matches OmniFocus Inbox perspective). + +**Filter logic:** Tasks with no project + not completed + not dropped + not deferred to future + +**Output:** JSON with count and task array (id, name, note, tags, dueDate) + +**Use when:** Starting inbox triage + +### get_tags.js +Returns full tag hierarchy with groupings. + +**Output:** JSON with all 129 tags organized by parent/children + +**Use when:** Need to find correct tags for a task + +### get_projects.js +Returns full project/folder structure. + +**Output:** JSON with projects and folder paths + +**Use when:** Need to find correct project for a task + +### add_task.js +Creates a new task with proper tags and project. + +**Parameters:** name, project, tags[], dueDate, deferDate, note, flagged + +**Use when:** Creating new tasks + +### update_task.js +Updates any existing task (not just inbox). + +**Parameters:** name or id, project, tags[], dueDate, deferDate + +**Use when:** Triaging/moving tasks, adding tags + +### create_tag.js +Creates a new tag, optionally under a parent. + +**Parameters:** name, parent (optional) + +**Use when:** Tag doesn't exist for a person or category + +## Tag Hierarchy Reference + +**Top-level categories:** +- **Activity** - What type of work (Creative, Coding, Writing, Reading, Research, etc.) +- **Energy** - Required mental state (Full Focus, Short Dashes, Brain Dead, Low, High) +- **Location** - Where to do it (Home, Grocery Stores, PSD Sites, Other Shopping) +- **People** - Who's involved (Personal family, PSD staff by department) +- **Groups** - Team meetings (Cabinet, Engineering Team, DLI Admin, etc.) +- **Time** - When to do it (Morning, Afternoon, Evening) +- **Communications** - How to communicate (Email, Phone, In Person, etc.) +- **Online** - Online tools (Freshservice, Github, Google Docs) +- **Standalone** - Follow Up, Waiting For, Waiting, Kiwanis + +**People → PSD breakdown:** +- Tech: Mel, Bill, Reese, Mark, Brad, Mason, Jordan, etc. +- DCRC: Jodi, Terri, Laura +- Comms: Danielle, Jake, Shana +- ESC: Ashley, John Y, Patrick, Krestin, James, Wendy, Janna, etc. +- SSOs: Moose, Brent + +**Special tags:** +- Geoffrey - tasks that AI can assist with +- Full Focus - requires dedicated focus time + +## Task Routing Rules + +### By Task Type → Project + +| Task Type | Project | Default Due | +|-----------|---------|-------------| +| Discussions with people | Meetings | 7 days | +| Phone calls | Meetings | 7 days | +| CoSN-related | CoSN Work | 7 days | +| Digital Promise work | Digital Promise | 7 days | +| AI/automation projects | AI Studio | 7 days | +| Coding/development | Coding Projects | 7 days | +| Research/learning | Research for Future Plans | 7 days | +| SOP/process development | Standard Operating Procedures | 14 days | +| Form/procedure updates | Department Procedures | 7 days | +| District reimbursements | Purchasing & Acquisitions | 7 days | +| Travel approvals | (appropriate project) | 14 days | +| Data governance | Data Governance | 14 days | +| Tech support issues | → Freshservice ticket | N/A | + +### By Task Type → Tags + +| Task Type | Tags | +|-----------|------| +| Discussion with person | [Person name], Follow Up | +| Phone call | Phone, Follow Up | +| Research tasks | Research | +| AI-assistable tasks | Geoffrey | +| Focus time needed | Full Focus | +| Admin/organizational | Organization | +| Safety/security related | (relevant ESC person) | + +### Routing Signals + +**Goes to Meetings project:** +- "talk to [person]" +- "discuss with" +- "follow up with" +- "check with" +- "call [person/org]" +- "get [thing] to [person]" + +**Goes to Research for Future Plans:** +- "look at/into" +- "what about" +- CISA resources +- Training to consider +- External resources to review + +**Goes to Coding Projects or AI Studio:** +- AI/automation ideas +- "build a program" +- Geoffrey capabilities +- Technical tools to explore + +**Needs Freshservice (skip for now):** +- User-reported issues +- Equipment requests +- "doesn't work/load" +- Form rebuild requests + +## Common Workflows + +### Add a Task + +1. Parse user request for: task name, person (if any), context clues + +2. Apply routing rules above to determine: + - **Project** - based on task type + - **Tags** - person + communication method + activity type + - **Due date** - based on task type timing + +3. If tag doesn't exist, create it with `create_tag.js` + +4. Run `add_task.js` with parameters + +5. Return standardized output + +**Example:** +``` +User: "Follow up with Mel about the drone program" + +Actions: +- Task: "Follow up with Mel about the drone program" +- Project: PSD > General Technology > Digital Innovation Leads +- Tags: Mel, Follow Up +- Due: Next 1:1 date or 7 days +``` + +### Triage Inbox + +1. **Get inbox tasks:** + ```bash + osascript -l JavaScript ./scripts/get_inbox.js + ``` + This returns only remaining tasks (no project, not completed, not dropped, not deferred) + +2. **Present assumptions in batches (10-15 tasks):** + - Read task notes for context clues + - Apply routing rules to suggest project, tags, due date + - Flag unclear tasks that need user input + +3. **Ask clarifying questions:** + - Who is [person/acronym]? + - Which project for [ambiguous task]? + - Should this be skipped (needs email context)? + +4. **Batch update confirmed tasks:** + ```bash + osascript -l JavaScript ./scripts/update_task.js '{"name":"...", "project":"...", "tags":[...], "dueDate":"..."}' + ``` + +5. **Create missing tags/projects as needed:** + ```bash + osascript -l JavaScript ./scripts/create_tag.js '{"name":"PersonName", "parent":"ESC"}' + ``` + +6. **Skip tasks that need:** + - Email context (user needs to read first) + - Freshservice ticket creation + - More information to route properly + +**Triage output format:** +```markdown +## My assumptions on remaining tasks: + +| # | Task | Project | Tags | Notes | +|---|------|---------|------|-------| +| 1 | task name | Meetings | Person, Follow Up | context | + +**Questions:** +- #X: Who is [person]? +- #Y: Which project for this? + +Which numbers need correction? +``` + +### Clean Up Tasks + +1. Find tasks that are: + - Overdue + - Stale (no activity) + - Missing tags + - In wrong project +2. Suggest actions: + - Complete + - Defer + - Delete + - Re-tag + - Move + +## Error Handling + +**If OmniFocus not running:** +``` +Status: ❌ Failed +Error: OmniFocus is not running. Please open OmniFocus and try again. +``` + +**If tag not found:** +- Check for similar tags (fuzzy match) +- Suggest creating new tag +- Ask user to clarify + +**If project not found:** +- List available projects in that domain +- Suggest closest match +- Ask user to specify + +## Output Format + +Always use standardized format: + +```markdown +## Summary +Created task with proper tags and project assignment + +## Actions +- Created task: "[task name]" +- Project: [full project path] +- Tags: [tag1, tag2, tag3] +- Due: [date] +- Notes: [if any] + +## Status +✅ Complete + +## Next Steps +- Task appears in [relevant perspective] +- Follow up scheduled for [date if applicable] +``` + +## Future Enhancements + +- [ ] Batch task creation +- [ ] Smart project suggestion based on content +- [ ] Calendar integration for due dates +- [ ] Recurring task patterns +- [ ] Perspective queries +- [ ] Task completion tracking diff --git a/skills/omnifocus-manager/scripts/add_task.js b/skills/omnifocus-manager/scripts/add_task.js new file mode 100644 index 0000000..1e1a61b --- /dev/null +++ b/skills/omnifocus-manager/scripts/add_task.js @@ -0,0 +1,106 @@ +#!/usr/bin/env osascript -l JavaScript + +// Add a task to OmniFocus using pure JXA (no URL scheme, no popups) +// Usage: osascript -l JavaScript add_task.js '{"name":"Task name","project":"Project Name","tags":["Tag1","Tag2"],"dueDate":"2025-11-25","note":"Optional note"}' + +function run(argv) { + const app = Application('OmniFocus'); + app.includeStandardAdditions = true; + + const doc = app.defaultDocument; + + // Parse input + let input; + try { + input = JSON.parse(argv[0]); + } catch (e) { + return JSON.stringify({ + success: false, + error: "Invalid JSON input. Expected: {name, project, tags, dueDate, note}" + }); + } + + const taskName = input.name; + const projectName = input.project; + const tagNames = input.tags || []; + const dueDateStr = input.dueDate; + const noteText = input.note || ""; + const deferDateStr = input.deferDate; + const flagged = input.flagged || false; + + if (!taskName) { + return JSON.stringify({ + success: false, + error: "Task name is required" + }); + } + + try { + // Build task properties + const taskProps = { + name: taskName, + note: noteText, + flagged: flagged + }; + + // Set dates if provided + if (dueDateStr) { + taskProps.dueDate = new Date(dueDateStr); + } + if (deferDateStr) { + taskProps.deferDate = new Date(deferDateStr); + } + + let task; + let targetLocation = "Inbox"; + + // Always create in inbox first + task = app.InboxTask(taskProps); + doc.inboxTasks.push(task); + + // Then move to project if specified + if (projectName) { + const projects = doc.flattenedProjects.whose({name: projectName}); + if (projects.length === 0) { + return JSON.stringify({ + success: false, + error: `Project not found: ${projectName}` + }); + } + const project = projects[0]; + // Move task to project + task.assignedContainer = project; + targetLocation = projectName; + } + + // Add tags (use app.add for existing objects, not push) + const addedTags = []; + for (const tagName of tagNames) { + const tags = doc.flattenedTags.whose({name: tagName}); + if (tags.length > 0) { + app.add(tags[0], {to: task.tags}); + addedTags.push(tagName); + } + } + + return JSON.stringify({ + success: true, + task: { + id: task.id(), + name: task.name(), + project: targetLocation, + tags: addedTags, + dueDate: dueDateStr || null, + deferDate: deferDateStr || null, + note: noteText || null, + flagged: flagged + } + }); + + } catch (e) { + return JSON.stringify({ + success: false, + error: `Failed to create task: ${e.message}` + }); + } +} diff --git a/skills/omnifocus-manager/scripts/create_tag.js b/skills/omnifocus-manager/scripts/create_tag.js new file mode 100644 index 0000000..fd1b17b --- /dev/null +++ b/skills/omnifocus-manager/scripts/create_tag.js @@ -0,0 +1,79 @@ +#!/usr/bin/env osascript -l JavaScript + +// Create a new tag in OmniFocus +// Usage: osascript -l JavaScript create_tag.js '{"name":"Tag Name","parent":"Parent Tag Name"}' + +function run(argv) { + const app = Application('OmniFocus'); + app.includeStandardAdditions = true; + const doc = app.defaultDocument; + + let input; + try { + input = JSON.parse(argv[0]); + } catch (e) { + return JSON.stringify({ + success: false, + error: "Invalid JSON input. Expected: {name, parent (optional)}" + }); + } + + const tagName = input.name; + const parentName = input.parent; + + if (!tagName) { + return JSON.stringify({ + success: false, + error: "Tag name is required" + }); + } + + try { + // Check if tag already exists + const existing = doc.flattenedTags.whose({name: tagName}); + if (existing.length > 0) { + return JSON.stringify({ + success: true, + tag: { + id: existing[0].id(), + name: existing[0].name(), + existed: true + } + }); + } + + // Create new tag + const newTag = app.Tag({name: tagName}); + + if (parentName) { + // Find parent tag and add as child + const parents = doc.flattenedTags.whose({name: parentName}); + if (parents.length === 0) { + return JSON.stringify({ + success: false, + error: "Parent tag not found: " + parentName + }); + } + parents[0].tags.push(newTag); + } else { + // Add to root tags + doc.tags.push(newTag); + } + + return JSON.stringify({ + success: true, + tag: { + id: newTag.id(), + name: newTag.name(), + parent: parentName || null, + existed: false + } + }); + + } catch (e) { + return JSON.stringify({ + success: false, + error: "Failed to create tag: " + e.message + }); + } +} diff --git a/skills/omnifocus-manager/scripts/get_inbox.js b/skills/omnifocus-manager/scripts/get_inbox.js new file mode 100644 index 0000000..5fbada6 --- /dev/null +++ b/skills/omnifocus-manager/scripts/get_inbox.js @@ -0,0 +1,30 @@ +#!/usr/bin/env osascript -l JavaScript + +// Get remaining inbox tasks (matches OmniFocus Inbox perspective) +// Usage: osascript -l JavaScript get_inbox.js + +function run(argv) { + var app = Application("OmniFocus"); + var doc = app.defaultDocument; + + var now = new Date(); + var tasks = doc.inboxTasks().filter(function(t) { + return t.assignedContainer() === null && + !t.completed() && + !t.dropped() && + (t.deferDate() === null || t.deferDate() <= now); + }).map(function(t) { + return { + id: t.id(), + name: t.name(), + note: t.note() ? t.note().substring(0, 200) : "", + tags: t.tags().map(function(tag) { return tag.name(); }), + dueDate: t.dueDate() ? t.dueDate().toISOString().split("T")[0] : null + }; + }); + + return JSON.stringify({ + count: tasks.length, + tasks: tasks + }, null, 2); +} diff --git a/skills/omnifocus-manager/scripts/get_projects.js b/skills/omnifocus-manager/scripts/get_projects.js new file mode 100644 index 0000000..c0caa55 --- /dev/null +++ b/skills/omnifocus-manager/scripts/get_projects.js @@ -0,0 +1,126 @@ +#!/usr/bin/env osascript -l JavaScript + +// Get all OmniFocus projects with full folder hierarchy +// Returns JSON with project names, folders, and structure + +function run() { + const app = Application('OmniFocus'); + app.includeStandardAdditions = true; + + const doc = app.defaultDocument; + const folders = doc.folders(); + const projects = doc.flattenedProjects(); + + // Build folder structure + const folderStructure = []; + + function processFolder(folder, depth = 0) { + const folderInfo = { + id: folder.id(), + name: folder.name(), + depth: depth, + projects: [], + subfolders: [] + }; + + // Get projects in this folder + try { + const folderProjects = folder.projects(); + for (let i = 0; i < folderProjects.length; i++) { + const proj = folderProjects[i]; + folderInfo.projects.push({ + id: proj.id(), + name: proj.name(), + status: proj.status(), + taskCount: proj.numberOfAvailableTasks() + }); + } + } catch (e) { + // No projects in folder + } + + // Get subfolders + try { + const subfolders = folder.folders(); + for (let i = 0; i < subfolders.length; i++) { + folderInfo.subfolders.push(processFolder(subfolders[i], depth + 1)); + } + } catch (e) { + // No subfolders + } + + return folderInfo; + } + + // Process top-level folders + for (let i = 0; i < folders.length; i++) { + folderStructure.push(processFolder(folders[i], 0)); + } + + // Get standalone projects (not in folders) + const standaloneProjects = []; + for (let i = 0; i < projects.length; i++) { + const proj = projects[i]; + try { + const container = proj.container(); + // If container is the document itself, it's standalone + if (container.class() === 'document') { + standaloneProjects.push({ + id: proj.id(), + name: proj.name(), + status: proj.status(), + taskCount: proj.numberOfAvailableTasks() + }); + } + } catch (e) { + // Skip if can't determine container + } + } + + // Build flat list for easy lookup + const flatList = []; + + function flattenStructure(folders, path = '') { + for (const folder of folders) { + const currentPath = path ? `${path} > ${folder.name}` : folder.name; + + for (const proj of folder.projects) { + flatList.push({ + id: proj.id, + name: proj.name, + path: `${currentPath} > ${proj.name}`, + folder: folder.name, + status: proj.status, + taskCount: proj.taskCount + }); + } + + if (folder.subfolders.length > 0) { + flattenStructure(folder.subfolders, currentPath); + } + } + } + + flattenStructure(folderStructure); + + // Add standalone projects + for (const proj of standaloneProjects) { + flatList.push({ + id: proj.id, + name: proj.name, + path: proj.name, + folder: null, + status: proj.status, + taskCount: proj.taskCount + }); + } + + const result = { + total_projects: flatList.length, + folder_structure: folderStructure, + standalone_projects: standaloneProjects, + flat_list: flatList + }; + + return JSON.stringify(result, null, 2); +} diff --git a/skills/omnifocus-manager/scripts/get_tags.js b/skills/omnifocus-manager/scripts/get_tags.js new file mode 100755 index 0000000..0248f38 --- /dev/null +++ b/skills/omnifocus-manager/scripts/get_tags.js @@ -0,0 +1,71 @@ +#!/usr/bin/env osascript -l JavaScript + +// Get all OmniFocus tags with full hierarchy +// Returns JSON with tag names, parents, children, and groupings + +function run() { + const app = Application('OmniFocus'); + app.includeStandardAdditions = true; + + const doc = app.defaultDocument; + const flattenedTags = doc.flattenedTags(); + + const tags = []; + + for (let i = 0; i < flattenedTags.length; i++) { + const tag = flattenedTags[i]; + + const tagInfo = { + id: tag.id(), + name: tag.name(), + parent: null, + children: [], + availableTaskCount: tag.availableTaskCount(), + remainingTaskCount: tag.remainingTaskCount() + }; + + // Get parent tag if exists + try { + const parent = tag.container(); + if (parent && parent.name) { + tagInfo.parent = parent.name(); + } + } catch (e) { + // No parent (top-level tag) + } + + // Get child tags + try { + const children = tag.tags(); + for (let j = 0; j < children.length; j++) { + tagInfo.children.push(children[j].name()); + } + } catch (e) { + // No children + } + + tags.push(tagInfo); + } + + // Build hierarchy structure + const hierarchy = {}; + const topLevel = []; + + for (const tag of tags) { + if (!tag.parent) { + topLevel.push(tag.name); + if (tag.children.length > 0) { + hierarchy[tag.name] = tag.children; + } + } + } + + const result = { + total_tags: tags.length, + top_level_tags: topLevel, + hierarchy: hierarchy, + all_tags: tags + }; + + return JSON.stringify(result, null, 2); +} diff --git a/skills/omnifocus-manager/scripts/update_task.js b/skills/omnifocus-manager/scripts/update_task.js new file mode 100644 index 0000000..6a9c5f8 --- /dev/null +++ b/skills/omnifocus-manager/scripts/update_task.js @@ -0,0 +1,108 @@ +#!/usr/bin/env osascript -l JavaScript + +// Update any task with project, tags, due date +// Usage: osascript -l JavaScript update_task.js '{"name":"Task name","project":"Project Name","tags":["Tag1"],"dueDate":"2025-11-28","deferDate":"2025-01-28"}' +// Can also use "id" instead of "name" to find task by ID + +function run(argv) { + const app = Application('OmniFocus'); + app.includeStandardAdditions = true; + const doc = app.defaultDocument; + + let input; + try { + input = JSON.parse(argv[0]); + } catch (e) { + return JSON.stringify({ + success: false, + error: "Invalid JSON input" + }); + } + + const taskId = input.id; + const taskName = input.name; + const projectName = input.project; + const tagNames = input.tags || []; + const dueDateStr = input.dueDate; + const deferDateStr = input.deferDate; + + if (!taskName && !taskId) { + return JSON.stringify({ + success: false, + error: "Task name or id is required" + }); + } + + try { + // Find the task - search all tasks, not just inbox + let tasksRef; + if (taskId) { + tasksRef = doc.flattenedTasks.whose({id: taskId}); + } else { + tasksRef = doc.flattenedTasks.whose({name: taskName}); + } + const tasks = tasksRef(); + + if (tasks.length === 0) { + return JSON.stringify({ + success: false, + error: "Task not found: " + (taskId || taskName) + }); + } + const task = tasks[0]; + + // Set dates if provided + if (dueDateStr) { + task.dueDate = new Date(dueDateStr); + } + if (deferDateStr) { + task.deferDate = new Date(deferDateStr); + } + + // Move to project if specified + let targetLocation = "Inbox"; + if (projectName) { + const projectsRef = doc.flattenedProjects.whose({name: projectName}); + const projects = projectsRef(); + if (projects.length === 0) { + return JSON.stringify({ + success: false, + error: "Project not found: " + projectName + }); + } + task.assignedContainer = projects[0]; + targetLocation = projectName; + } + + // Add tags (preserves existing tags) + const addedTags = []; + for (const tagName of tagNames) { + const tags = doc.flattenedTags.whose({name: tagName}); + if (tags.length > 0) { + app.add(tags[0], {to: task.tags}); + addedTags.push(tagName); + } + } + + // Get all current tags on task + const allTags = task.tags().map(function(t) { return t.name(); }); + + return JSON.stringify({ + success: true, + task: { + id: task.id(), + name: task.name(), + project: targetLocation, + tags: allTags, + dueDate: dueDateStr || null, + deferDate: deferDateStr || null + } + }); + + } catch (e) { + return JSON.stringify({ + success: false, + error: "Failed to update task: " + e.message + }); + } +} diff --git a/skills/pdf/LICENSE.txt b/skills/pdf/LICENSE.txt new file mode 100644 index 0000000..c55ab42 --- /dev/null +++ b/skills/pdf/LICENSE.txt @@ -0,0 +1,30 @@ +© 2025 Anthropic, PBC. All rights reserved. + +LICENSE: Use of these materials (including all code, prompts, assets, files, +and other components of this Skill) is governed by your agreement with +Anthropic regarding use of Anthropic's services. If no separate agreement +exists, use is governed by Anthropic's Consumer Terms of Service or +Commercial Terms of Service, as applicable: +https://www.anthropic.com/legal/consumer-terms +https://www.anthropic.com/legal/commercial-terms +Your applicable agreement is referred to as the "Agreement." "Services" are +as defined in the Agreement. + +ADDITIONAL RESTRICTIONS: Notwithstanding anything in the Agreement to the +contrary, users may not: + +- Extract these materials from the Services or retain copies of these + materials outside the Services +- Reproduce or copy these materials, except for temporary copies created + automatically during authorized use of the Services +- Create derivative works based on these materials +- Distribute, sublicense, or transfer these materials to any third party +- Make, offer to sell, sell, or import any inventions embodied in these + materials +- Reverse engineer, decompile, or disassemble these materials + +The receipt, viewing, or possession of these materials does not convey or +imply any license or right beyond those expressly granted above. + +Anthropic retains all right, title, and interest in these materials, +including all copyrights, patents, and other intellectual property rights. diff --git a/skills/pdf/SKILL.md b/skills/pdf/SKILL.md new file mode 100644 index 0000000..a996d52 --- /dev/null +++ b/skills/pdf/SKILL.md @@ -0,0 +1,303 @@ +--- +name: pdf +description: Comprehensive PDF manipulation toolkit for extracting text and tables, creating new PDFs, merging/splitting documents, and handling forms. When Claude needs to fill in a PDF form or programmatically process, generate, or analyze PDF documents at scale. +triggers: + - "pdf" + - "fill pdf form" + - "extract pdf" + - "merge pdf" + - "split pdf" + - ".pdf" +allowed-tools: Read, Write, Edit, Bash, Glob +version: 1.0.0 +license: Proprietary. LICENSE.txt has complete terms +--- + +# PDF Processing Guide + +## Overview + +This guide covers essential PDF processing operations using Python libraries and command-line tools. For advanced features, JavaScript libraries, and detailed examples, see reference.md. If you need to fill out a PDF form, read forms.md and follow its instructions. + +## Quick Start + +```python +from pypdf import PdfReader, PdfWriter + +# Read a PDF +reader = PdfReader("document.pdf") +print(f"Pages: {len(reader.pages)}") + +# Extract text +text = "" +for page in reader.pages: + text += page.extract_text() +``` + +## Python Libraries + +### pypdf - Basic Operations + +#### Merge PDFs +```python +from pypdf import PdfWriter, PdfReader + +writer = PdfWriter() +for pdf_file in ["doc1.pdf", "doc2.pdf", "doc3.pdf"]: + reader = PdfReader(pdf_file) + for page in reader.pages: + writer.add_page(page) + +with open("merged.pdf", "wb") as output: + writer.write(output) +``` + +#### Split PDF +```python +reader = PdfReader("input.pdf") +for i, page in enumerate(reader.pages): + writer = PdfWriter() + writer.add_page(page) + with open(f"page_{i+1}.pdf", "wb") as output: + writer.write(output) +``` + +#### Extract Metadata +```python +reader = PdfReader("document.pdf") +meta = reader.metadata +print(f"Title: {meta.title}") +print(f"Author: {meta.author}") +print(f"Subject: {meta.subject}") +print(f"Creator: {meta.creator}") +``` + +#### Rotate Pages +```python +reader = PdfReader("input.pdf") +writer = PdfWriter() + +page = reader.pages[0] +page.rotate(90) # Rotate 90 degrees clockwise +writer.add_page(page) + +with open("rotated.pdf", "wb") as output: + writer.write(output) +``` + +### pdfplumber - Text and Table Extraction + +#### Extract Text with Layout +```python +import pdfplumber + +with pdfplumber.open("document.pdf") as pdf: + for page in pdf.pages: + text = page.extract_text() + print(text) +``` + +#### Extract Tables +```python +with pdfplumber.open("document.pdf") as pdf: + for i, page in enumerate(pdf.pages): + tables = page.extract_tables() + for j, table in enumerate(tables): + print(f"Table {j+1} on page {i+1}:") + for row in table: + print(row) +``` + +#### Advanced Table Extraction +```python +import pandas as pd + +with pdfplumber.open("document.pdf") as pdf: + all_tables = [] + for page in pdf.pages: + tables = page.extract_tables() + for table in tables: + if table: # Check if table is not empty + df = pd.DataFrame(table[1:], columns=table[0]) + all_tables.append(df) + +# Combine all tables +if all_tables: + combined_df = pd.concat(all_tables, ignore_index=True) + combined_df.to_excel("extracted_tables.xlsx", index=False) +``` + +### reportlab - Create PDFs + +#### Basic PDF Creation +```python +from reportlab.lib.pagesizes import letter +from reportlab.pdfgen import canvas + +c = canvas.Canvas("hello.pdf", pagesize=letter) +width, height = letter + +# Add text +c.drawString(100, height - 100, "Hello World!") +c.drawString(100, height - 120, "This is a PDF created with reportlab") + +# Add a line +c.line(100, height - 140, 400, height - 140) + +# Save +c.save() +``` + +#### Create PDF with Multiple Pages +```python +from reportlab.lib.pagesizes import letter +from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak +from reportlab.lib.styles import getSampleStyleSheet + +doc = SimpleDocTemplate("report.pdf", pagesize=letter) +styles = getSampleStyleSheet() +story = [] + +# Add content +title = Paragraph("Report Title", styles['Title']) +story.append(title) +story.append(Spacer(1, 12)) + +body = Paragraph("This is the body of the report. " * 20, styles['Normal']) +story.append(body) +story.append(PageBreak()) + +# Page 2 +story.append(Paragraph("Page 2", styles['Heading1'])) +story.append(Paragraph("Content for page 2", styles['Normal'])) + +# Build PDF +doc.build(story) +``` + +## Command-Line Tools + +### pdftotext (poppler-utils) +```bash +# Extract text +pdftotext input.pdf output.txt + +# Extract text preserving layout +pdftotext -layout input.pdf output.txt + +# Extract specific pages +pdftotext -f 1 -l 5 input.pdf output.txt # Pages 1-5 +``` + +### qpdf +```bash +# Merge PDFs +qpdf --empty --pages file1.pdf file2.pdf -- merged.pdf + +# Split pages +qpdf input.pdf --pages . 1-5 -- pages1-5.pdf +qpdf input.pdf --pages . 6-10 -- pages6-10.pdf + +# Rotate pages +qpdf input.pdf output.pdf --rotate=+90:1 # Rotate page 1 by 90 degrees + +# Remove password +qpdf --password=mypassword --decrypt encrypted.pdf decrypted.pdf +``` + +### pdftk (if available) +```bash +# Merge +pdftk file1.pdf file2.pdf cat output merged.pdf + +# Split +pdftk input.pdf burst + +# Rotate +pdftk input.pdf rotate 1east output rotated.pdf +``` + +## Common Tasks + +### Extract Text from Scanned PDFs +```python +# Requires: pip install pytesseract pdf2image +import pytesseract +from pdf2image import convert_from_path + +# Convert PDF to images +images = convert_from_path('scanned.pdf') + +# OCR each page +text = "" +for i, image in enumerate(images): + text += f"Page {i+1}:\n" + text += pytesseract.image_to_string(image) + text += "\n\n" + +print(text) +``` + +### Add Watermark +```python +from pypdf import PdfReader, PdfWriter + +# Create watermark (or load existing) +watermark = PdfReader("watermark.pdf").pages[0] + +# Apply to all pages +reader = PdfReader("document.pdf") +writer = PdfWriter() + +for page in reader.pages: + page.merge_page(watermark) + writer.add_page(page) + +with open("watermarked.pdf", "wb") as output: + writer.write(output) +``` + +### Extract Images +```bash +# Using pdfimages (poppler-utils) +pdfimages -j input.pdf output_prefix + +# This extracts all images as output_prefix-000.jpg, output_prefix-001.jpg, etc. +``` + +### Password Protection +```python +from pypdf import PdfReader, PdfWriter + +reader = PdfReader("input.pdf") +writer = PdfWriter() + +for page in reader.pages: + writer.add_page(page) + +# Add password +writer.encrypt("userpassword", "ownerpassword") + +with open("encrypted.pdf", "wb") as output: + writer.write(output) +``` + +## Quick Reference + +| Task | Best Tool | Command/Code | +|------|-----------|--------------| +| Merge PDFs | pypdf | `writer.add_page(page)` | +| Split PDFs | pypdf | One page per file | +| Extract text | pdfplumber | `page.extract_text()` | +| Extract tables | pdfplumber | `page.extract_tables()` | +| Create PDFs | reportlab | Canvas or Platypus | +| Command line merge | qpdf | `qpdf --empty --pages ...` | +| OCR scanned PDFs | pytesseract | Convert to image first | +| Fill PDF forms | pdf-lib or pypdf (see forms.md) | See forms.md | + +## Next Steps + +- For advanced pypdfium2 usage, see reference.md +- For JavaScript libraries (pdf-lib), see reference.md +- If you need to fill out a PDF form, follow the instructions in forms.md +- For troubleshooting guides, see reference.md diff --git a/skills/pdf/forms.md b/skills/pdf/forms.md new file mode 100644 index 0000000..4e23450 --- /dev/null +++ b/skills/pdf/forms.md @@ -0,0 +1,205 @@ +**CRITICAL: You MUST complete these steps in order. Do not skip ahead to writing code.** + +If you need to fill out a PDF form, first check to see if the PDF has fillable form fields. Run this script from this file's directory: + `python scripts/check_fillable_fields <file.pdf>`, and depending on the result go to either the "Fillable fields" or "Non-fillable fields" and follow those instructions. + +# Fillable fields +If the PDF has fillable form fields: +- Run this script from this file's directory: `python scripts/extract_form_field_info.py <input.pdf> <field_info.json>`. It will create a JSON file with a list of fields in this format: +``` +[ + { + "field_id": (unique ID for the field), + "page": (page number, 1-based), + "rect": ([left, bottom, right, top] bounding box in PDF coordinates, y=0 is the bottom of the page), + "type": ("text", "checkbox", "radio_group", or "choice"), + }, + // Checkboxes have "checked_value" and "unchecked_value" properties: + { + "field_id": (unique ID for the field), + "page": (page number, 1-based), + "type": "checkbox", + "checked_value": (Set the field to this value to check the checkbox), + "unchecked_value": (Set the field to this value to uncheck the checkbox), + }, + // Radio groups have a "radio_options" list with the possible choices. + { + "field_id": (unique ID for the field), + "page": (page number, 1-based), + "type": "radio_group", + "radio_options": [ + { + "value": (set the field to this value to select this radio option), + "rect": (bounding box for the radio button for this option) + }, + // Other radio options + ] + }, + // Multiple choice fields have a "choice_options" list with the possible choices: + { + "field_id": (unique ID for the field), + "page": (page number, 1-based), + "type": "choice", + "choice_options": [ + { + "value": (set the field to this value to select this option), + "text": (display text of the option) + }, + // Other choice options + ], + } +] +``` +- Convert the PDF to PNGs (one image for each page) with this script (run from this file's directory): +`python scripts/convert_pdf_to_images.py <file.pdf> <output_directory>` +Then analyze the images to determine the purpose of each form field (make sure to convert the bounding box PDF coordinates to image coordinates). +- Create a `field_values.json` file in this format with the values to be entered for each field: +``` +[ + { + "field_id": "last_name", // Must match the field_id from `extract_form_field_info.py` + "description": "The user's last name", + "page": 1, // Must match the "page" value in field_info.json + "value": "Simpson" + }, + { + "field_id": "Checkbox12", + "description": "Checkbox to be checked if the user is 18 or over", + "page": 1, + "value": "/On" // If this is a checkbox, use its "checked_value" value to check it. If it's a radio button group, use one of the "value" values in "radio_options". + }, + // more fields +] +``` +- Run the `fill_fillable_fields.py` script from this file's directory to create a filled-in PDF: +`python scripts/fill_fillable_fields.py <input pdf> <field_values.json> <output pdf>` +This script will verify that the field IDs and values you provide are valid; if it prints error messages, correct the appropriate fields and try again. + +# Non-fillable fields +If the PDF doesn't have fillable form fields, you'll need to visually determine where the data should be added and create text annotations. Follow the below steps *exactly*. You MUST perform all of these steps to ensure that the the form is accurately completed. Details for each step are below. +- Convert the PDF to PNG images and determine field bounding boxes. +- Create a JSON file with field information and validation images showing the bounding boxes. +- Validate the the bounding boxes. +- Use the bounding boxes to fill in the form. + +## Step 1: Visual Analysis (REQUIRED) +- Convert the PDF to PNG images. Run this script from this file's directory: +`python scripts/convert_pdf_to_images.py <file.pdf> <output_directory>` +The script will create a PNG image for each page in the PDF. +- Carefully examine each PNG image and identify all form fields and areas where the user should enter data. For each form field where the user should enter text, determine bounding boxes for both the form field label, and the area where the user should enter text. The label and entry bounding boxes MUST NOT INTERSECT; the text entry box should only include the area where data should be entered. Usually this area will be immediately to the side, above, or below its label. Entry bounding boxes must be tall and wide enough to contain their text. + +These are some examples of form structures that you might see: + +*Label inside box* +``` +┌────────────────────────┐ +│ Name: │ +└────────────────────────┘ +``` +The input area should be to the right of the "Name" label and extend to the edge of the box. + +*Label before line* +``` +Email: _______________________ +``` +The input area should be above the line and include its entire width. + +*Label under line* +``` +_________________________ +Name +``` +The input area should be above the line and include the entire width of the line. This is common for signature and date fields. + +*Label above line* +``` +Please enter any special requests: +________________________________________________ +``` +The input area should extend from the bottom of the label to the line, and should include the entire width of the line. + +*Checkboxes* +``` +Are you a US citizen? Yes □ No □ +``` +For checkboxes: +- Look for small square boxes (□) - these are the actual checkboxes to target. They may be to the left or right of their labels. +- Distinguish between label text ("Yes", "No") and the clickable checkbox squares. +- The entry bounding box should cover ONLY the small square, not the text label. + +### Step 2: Create fields.json and validation images (REQUIRED) +- Create a file named `fields.json` with information for the form fields and bounding boxes in this format: +``` +{ + "pages": [ + { + "page_number": 1, + "image_width": (first page image width in pixels), + "image_height": (first page image height in pixels), + }, + { + "page_number": 2, + "image_width": (second page image width in pixels), + "image_height": (second page image height in pixels), + } + // additional pages + ], + "form_fields": [ + // Example for a text field. + { + "page_number": 1, + "description": "The user's last name should be entered here", + // Bounding boxes are [left, top, right, bottom]. The bounding boxes for the label and text entry should not overlap. + "field_label": "Last name", + "label_bounding_box": [30, 125, 95, 142], + "entry_bounding_box": [100, 125, 280, 142], + "entry_text": { + "text": "Johnson", // This text will be added as an annotation at the entry_bounding_box location + "font_size": 14, // optional, defaults to 14 + "font_color": "000000", // optional, RRGGBB format, defaults to 000000 (black) + } + }, + // Example for a checkbox. TARGET THE SQUARE for the entry bounding box, NOT THE TEXT + { + "page_number": 2, + "description": "Checkbox that should be checked if the user is over 18", + "entry_bounding_box": [140, 525, 155, 540], // Small box over checkbox square + "field_label": "Yes", + "label_bounding_box": [100, 525, 132, 540], // Box containing "Yes" text + // Use "X" to check a checkbox. + "entry_text": { + "text": "X", + } + } + // additional form field entries + ] +} +``` + +Create validation images by running this script from this file's directory for each page: +`python scripts/create_validation_image.py <page_number> <path_to_fields.json> <input_image_path> <output_image_path> + +The validation images will have red rectangles where text should be entered, and blue rectangles covering label text. + +### Step 3: Validate Bounding Boxes (REQUIRED) +#### Automated intersection check +- Verify that none of bounding boxes intersect and that the entry bounding boxes are tall enough by checking the fields.json file with the `check_bounding_boxes.py` script (run from this file's directory): +`python scripts/check_bounding_boxes.py <JSON file>` + +If there are errors, reanalyze the relevant fields, adjust the bounding boxes, and iterate until there are no remaining errors. Remember: label (blue) bounding boxes should contain text labels, entry (red) boxes should not. + +#### Manual image inspection +**CRITICAL: Do not proceed without visually inspecting validation images** +- Red rectangles must ONLY cover input areas +- Red rectangles MUST NOT contain any text +- Blue rectangles should contain label text +- For checkboxes: + - Red rectangle MUST be centered on the checkbox square + - Blue rectangle should cover the text label for the checkbox + +- If any rectangles look wrong, fix fields.json, regenerate the validation images, and verify again. Repeat this process until the bounding boxes are fully accurate. + + +### Step 4: Add annotations to the PDF +Run this script from this file's directory to create a filled-out PDF using the information in fields.json: +`python scripts/fill_pdf_form_with_annotations.py <input_pdf_path> <path_to_fields.json> <output_pdf_path> diff --git a/skills/pdf/reference.md b/skills/pdf/reference.md new file mode 100644 index 0000000..41400bf --- /dev/null +++ b/skills/pdf/reference.md @@ -0,0 +1,612 @@ +# PDF Processing Advanced Reference + +This document contains advanced PDF processing features, detailed examples, and additional libraries not covered in the main skill instructions. + +## pypdfium2 Library (Apache/BSD License) + +### Overview +pypdfium2 is a Python binding for PDFium (Chromium's PDF library). It's excellent for fast PDF rendering, image generation, and serves as a PyMuPDF replacement. + +### Render PDF to Images +```python +import pypdfium2 as pdfium +from PIL import Image + +# Load PDF +pdf = pdfium.PdfDocument("document.pdf") + +# Render page to image +page = pdf[0] # First page +bitmap = page.render( + scale=2.0, # Higher resolution + rotation=0 # No rotation +) + +# Convert to PIL Image +img = bitmap.to_pil() +img.save("page_1.png", "PNG") + +# Process multiple pages +for i, page in enumerate(pdf): + bitmap = page.render(scale=1.5) + img = bitmap.to_pil() + img.save(f"page_{i+1}.jpg", "JPEG", quality=90) +``` + +### Extract Text with pypdfium2 +```python +import pypdfium2 as pdfium + +pdf = pdfium.PdfDocument("document.pdf") +for i, page in enumerate(pdf): + text = page.get_text() + print(f"Page {i+1} text length: {len(text)} chars") +``` + +## JavaScript Libraries + +### pdf-lib (MIT License) + +pdf-lib is a powerful JavaScript library for creating and modifying PDF documents in any JavaScript environment. + +#### Load and Manipulate Existing PDF +```javascript +import { PDFDocument } from 'pdf-lib'; +import fs from 'fs'; + +async function manipulatePDF() { + // Load existing PDF + const existingPdfBytes = fs.readFileSync('input.pdf'); + const pdfDoc = await PDFDocument.load(existingPdfBytes); + + // Get page count + const pageCount = pdfDoc.getPageCount(); + console.log(`Document has ${pageCount} pages`); + + // Add new page + const newPage = pdfDoc.addPage([600, 400]); + newPage.drawText('Added by pdf-lib', { + x: 100, + y: 300, + size: 16 + }); + + // Save modified PDF + const pdfBytes = await pdfDoc.save(); + fs.writeFileSync('modified.pdf', pdfBytes); +} +``` + +#### Create Complex PDFs from Scratch +```javascript +import { PDFDocument, rgb, StandardFonts } from 'pdf-lib'; +import fs from 'fs'; + +async function createPDF() { + const pdfDoc = await PDFDocument.create(); + + // Add fonts + const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica); + const helveticaBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold); + + // Add page + const page = pdfDoc.addPage([595, 842]); // A4 size + const { width, height } = page.getSize(); + + // Add text with styling + page.drawText('Invoice #12345', { + x: 50, + y: height - 50, + size: 18, + font: helveticaBold, + color: rgb(0.2, 0.2, 0.8) + }); + + // Add rectangle (header background) + page.drawRectangle({ + x: 40, + y: height - 100, + width: width - 80, + height: 30, + color: rgb(0.9, 0.9, 0.9) + }); + + // Add table-like content + const items = [ + ['Item', 'Qty', 'Price', 'Total'], + ['Widget', '2', '$50', '$100'], + ['Gadget', '1', '$75', '$75'] + ]; + + let yPos = height - 150; + items.forEach(row => { + let xPos = 50; + row.forEach(cell => { + page.drawText(cell, { + x: xPos, + y: yPos, + size: 12, + font: helveticaFont + }); + xPos += 120; + }); + yPos -= 25; + }); + + const pdfBytes = await pdfDoc.save(); + fs.writeFileSync('created.pdf', pdfBytes); +} +``` + +#### Advanced Merge and Split Operations +```javascript +import { PDFDocument } from 'pdf-lib'; +import fs from 'fs'; + +async function mergePDFs() { + // Create new document + const mergedPdf = await PDFDocument.create(); + + // Load source PDFs + const pdf1Bytes = fs.readFileSync('doc1.pdf'); + const pdf2Bytes = fs.readFileSync('doc2.pdf'); + + const pdf1 = await PDFDocument.load(pdf1Bytes); + const pdf2 = await PDFDocument.load(pdf2Bytes); + + // Copy pages from first PDF + const pdf1Pages = await mergedPdf.copyPages(pdf1, pdf1.getPageIndices()); + pdf1Pages.forEach(page => mergedPdf.addPage(page)); + + // Copy specific pages from second PDF (pages 0, 2, 4) + const pdf2Pages = await mergedPdf.copyPages(pdf2, [0, 2, 4]); + pdf2Pages.forEach(page => mergedPdf.addPage(page)); + + const mergedPdfBytes = await mergedPdf.save(); + fs.writeFileSync('merged.pdf', mergedPdfBytes); +} +``` + +### pdfjs-dist (Apache License) + +PDF.js is Mozilla's JavaScript library for rendering PDFs in the browser. + +#### Basic PDF Loading and Rendering +```javascript +import * as pdfjsLib from 'pdfjs-dist'; + +// Configure worker (important for performance) +pdfjsLib.GlobalWorkerOptions.workerSrc = './pdf.worker.js'; + +async function renderPDF() { + // Load PDF + const loadingTask = pdfjsLib.getDocument('document.pdf'); + const pdf = await loadingTask.promise; + + console.log(`Loaded PDF with ${pdf.numPages} pages`); + + // Get first page + const page = await pdf.getPage(1); + const viewport = page.getViewport({ scale: 1.5 }); + + // Render to canvas + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + canvas.height = viewport.height; + canvas.width = viewport.width; + + const renderContext = { + canvasContext: context, + viewport: viewport + }; + + await page.render(renderContext).promise; + document.body.appendChild(canvas); +} +``` + +#### Extract Text with Coordinates +```javascript +import * as pdfjsLib from 'pdfjs-dist'; + +async function extractText() { + const loadingTask = pdfjsLib.getDocument('document.pdf'); + const pdf = await loadingTask.promise; + + let fullText = ''; + + // Extract text from all pages + for (let i = 1; i <= pdf.numPages; i++) { + const page = await pdf.getPage(i); + const textContent = await page.getTextContent(); + + const pageText = textContent.items + .map(item => item.str) + .join(' '); + + fullText += `\n--- Page ${i} ---\n${pageText}`; + + // Get text with coordinates for advanced processing + const textWithCoords = textContent.items.map(item => ({ + text: item.str, + x: item.transform[4], + y: item.transform[5], + width: item.width, + height: item.height + })); + } + + console.log(fullText); + return fullText; +} +``` + +#### Extract Annotations and Forms +```javascript +import * as pdfjsLib from 'pdfjs-dist'; + +async function extractAnnotations() { + const loadingTask = pdfjsLib.getDocument('annotated.pdf'); + const pdf = await loadingTask.promise; + + for (let i = 1; i <= pdf.numPages; i++) { + const page = await pdf.getPage(i); + const annotations = await page.getAnnotations(); + + annotations.forEach(annotation => { + console.log(`Annotation type: ${annotation.subtype}`); + console.log(`Content: ${annotation.contents}`); + console.log(`Coordinates: ${JSON.stringify(annotation.rect)}`); + }); + } +} +``` + +## Advanced Command-Line Operations + +### poppler-utils Advanced Features + +#### Extract Text with Bounding Box Coordinates +```bash +# Extract text with bounding box coordinates (essential for structured data) +pdftotext -bbox-layout document.pdf output.xml + +# The XML output contains precise coordinates for each text element +``` + +#### Advanced Image Conversion +```bash +# Convert to PNG images with specific resolution +pdftoppm -png -r 300 document.pdf output_prefix + +# Convert specific page range with high resolution +pdftoppm -png -r 600 -f 1 -l 3 document.pdf high_res_pages + +# Convert to JPEG with quality setting +pdftoppm -jpeg -jpegopt quality=85 -r 200 document.pdf jpeg_output +``` + +#### Extract Embedded Images +```bash +# Extract all embedded images with metadata +pdfimages -j -p document.pdf page_images + +# List image info without extracting +pdfimages -list document.pdf + +# Extract images in their original format +pdfimages -all document.pdf images/img +``` + +### qpdf Advanced Features + +#### Complex Page Manipulation +```bash +# Split PDF into groups of pages +qpdf --split-pages=3 input.pdf output_group_%02d.pdf + +# Extract specific pages with complex ranges +qpdf input.pdf --pages input.pdf 1,3-5,8,10-end -- extracted.pdf + +# Merge specific pages from multiple PDFs +qpdf --empty --pages doc1.pdf 1-3 doc2.pdf 5-7 doc3.pdf 2,4 -- combined.pdf +``` + +#### PDF Optimization and Repair +```bash +# Optimize PDF for web (linearize for streaming) +qpdf --linearize input.pdf optimized.pdf + +# Remove unused objects and compress +qpdf --optimize-level=all input.pdf compressed.pdf + +# Attempt to repair corrupted PDF structure +qpdf --check input.pdf +qpdf --fix-qdf damaged.pdf repaired.pdf + +# Show detailed PDF structure for debugging +qpdf --show-all-pages input.pdf > structure.txt +``` + +#### Advanced Encryption +```bash +# Add password protection with specific permissions +qpdf --encrypt user_pass owner_pass 256 --print=none --modify=none -- input.pdf encrypted.pdf + +# Check encryption status +qpdf --show-encryption encrypted.pdf + +# Remove password protection (requires password) +qpdf --password=secret123 --decrypt encrypted.pdf decrypted.pdf +``` + +## Advanced Python Techniques + +### pdfplumber Advanced Features + +#### Extract Text with Precise Coordinates +```python +import pdfplumber + +with pdfplumber.open("document.pdf") as pdf: + page = pdf.pages[0] + + # Extract all text with coordinates + chars = page.chars + for char in chars[:10]: # First 10 characters + print(f"Char: '{char['text']}' at x:{char['x0']:.1f} y:{char['y0']:.1f}") + + # Extract text by bounding box (left, top, right, bottom) + bbox_text = page.within_bbox((100, 100, 400, 200)).extract_text() +``` + +#### Advanced Table Extraction with Custom Settings +```python +import pdfplumber +import pandas as pd + +with pdfplumber.open("complex_table.pdf") as pdf: + page = pdf.pages[0] + + # Extract tables with custom settings for complex layouts + table_settings = { + "vertical_strategy": "lines", + "horizontal_strategy": "lines", + "snap_tolerance": 3, + "intersection_tolerance": 15 + } + tables = page.extract_tables(table_settings) + + # Visual debugging for table extraction + img = page.to_image(resolution=150) + img.save("debug_layout.png") +``` + +### reportlab Advanced Features + +#### Create Professional Reports with Tables +```python +from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph +from reportlab.lib.styles import getSampleStyleSheet +from reportlab.lib import colors + +# Sample data +data = [ + ['Product', 'Q1', 'Q2', 'Q3', 'Q4'], + ['Widgets', '120', '135', '142', '158'], + ['Gadgets', '85', '92', '98', '105'] +] + +# Create PDF with table +doc = SimpleDocTemplate("report.pdf") +elements = [] + +# Add title +styles = getSampleStyleSheet() +title = Paragraph("Quarterly Sales Report", styles['Title']) +elements.append(title) + +# Add table with advanced styling +table = Table(data) +table.setStyle(TableStyle([ + ('BACKGROUND', (0, 0), (-1, 0), colors.grey), + ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), + ('ALIGN', (0, 0), (-1, -1), 'CENTER'), + ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), + ('FONTSIZE', (0, 0), (-1, 0), 14), + ('BOTTOMPADDING', (0, 0), (-1, 0), 12), + ('BACKGROUND', (0, 1), (-1, -1), colors.beige), + ('GRID', (0, 0), (-1, -1), 1, colors.black) +])) +elements.append(table) + +doc.build(elements) +``` + +## Complex Workflows + +### Extract Figures/Images from PDF + +#### Method 1: Using pdfimages (fastest) +```bash +# Extract all images with original quality +pdfimages -all document.pdf images/img +``` + +#### Method 2: Using pypdfium2 + Image Processing +```python +import pypdfium2 as pdfium +from PIL import Image +import numpy as np + +def extract_figures(pdf_path, output_dir): + pdf = pdfium.PdfDocument(pdf_path) + + for page_num, page in enumerate(pdf): + # Render high-resolution page + bitmap = page.render(scale=3.0) + img = bitmap.to_pil() + + # Convert to numpy for processing + img_array = np.array(img) + + # Simple figure detection (non-white regions) + mask = np.any(img_array != [255, 255, 255], axis=2) + + # Find contours and extract bounding boxes + # (This is simplified - real implementation would need more sophisticated detection) + + # Save detected figures + # ... implementation depends on specific needs +``` + +### Batch PDF Processing with Error Handling +```python +import os +import glob +from pypdf import PdfReader, PdfWriter +import logging + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +def batch_process_pdfs(input_dir, operation='merge'): + pdf_files = glob.glob(os.path.join(input_dir, "*.pdf")) + + if operation == 'merge': + writer = PdfWriter() + for pdf_file in pdf_files: + try: + reader = PdfReader(pdf_file) + for page in reader.pages: + writer.add_page(page) + logger.info(f"Processed: {pdf_file}") + except Exception as e: + logger.error(f"Failed to process {pdf_file}: {e}") + continue + + with open("batch_merged.pdf", "wb") as output: + writer.write(output) + + elif operation == 'extract_text': + for pdf_file in pdf_files: + try: + reader = PdfReader(pdf_file) + text = "" + for page in reader.pages: + text += page.extract_text() + + output_file = pdf_file.replace('.pdf', '.txt') + with open(output_file, 'w', encoding='utf-8') as f: + f.write(text) + logger.info(f"Extracted text from: {pdf_file}") + + except Exception as e: + logger.error(f"Failed to extract text from {pdf_file}: {e}") + continue +``` + +### Advanced PDF Cropping +```python +from pypdf import PdfWriter, PdfReader + +reader = PdfReader("input.pdf") +writer = PdfWriter() + +# Crop page (left, bottom, right, top in points) +page = reader.pages[0] +page.mediabox.left = 50 +page.mediabox.bottom = 50 +page.mediabox.right = 550 +page.mediabox.top = 750 + +writer.add_page(page) +with open("cropped.pdf", "wb") as output: + writer.write(output) +``` + +## Performance Optimization Tips + +### 1. For Large PDFs +- Use streaming approaches instead of loading entire PDF in memory +- Use `qpdf --split-pages` for splitting large files +- Process pages individually with pypdfium2 + +### 2. For Text Extraction +- `pdftotext -bbox-layout` is fastest for plain text extraction +- Use pdfplumber for structured data and tables +- Avoid `pypdf.extract_text()` for very large documents + +### 3. For Image Extraction +- `pdfimages` is much faster than rendering pages +- Use low resolution for previews, high resolution for final output + +### 4. For Form Filling +- pdf-lib maintains form structure better than most alternatives +- Pre-validate form fields before processing + +### 5. Memory Management +```python +# Process PDFs in chunks +def process_large_pdf(pdf_path, chunk_size=10): + reader = PdfReader(pdf_path) + total_pages = len(reader.pages) + + for start_idx in range(0, total_pages, chunk_size): + end_idx = min(start_idx + chunk_size, total_pages) + writer = PdfWriter() + + for i in range(start_idx, end_idx): + writer.add_page(reader.pages[i]) + + # Process chunk + with open(f"chunk_{start_idx//chunk_size}.pdf", "wb") as output: + writer.write(output) +``` + +## Troubleshooting Common Issues + +### Encrypted PDFs +```python +# Handle password-protected PDFs +from pypdf import PdfReader + +try: + reader = PdfReader("encrypted.pdf") + if reader.is_encrypted: + reader.decrypt("password") +except Exception as e: + print(f"Failed to decrypt: {e}") +``` + +### Corrupted PDFs +```bash +# Use qpdf to repair +qpdf --check corrupted.pdf +qpdf --replace-input corrupted.pdf +``` + +### Text Extraction Issues +```python +# Fallback to OCR for scanned PDFs +import pytesseract +from pdf2image import convert_from_path + +def extract_text_with_ocr(pdf_path): + images = convert_from_path(pdf_path) + text = "" + for i, image in enumerate(images): + text += pytesseract.image_to_string(image) + return text +``` + +## License Information + +- **pypdf**: BSD License +- **pdfplumber**: MIT License +- **pypdfium2**: Apache/BSD License +- **reportlab**: BSD License +- **poppler-utils**: GPL-2 License +- **qpdf**: Apache License +- **pdf-lib**: MIT License +- **pdfjs-dist**: Apache License \ No newline at end of file diff --git a/skills/pdf/scripts/check_bounding_boxes.py b/skills/pdf/scripts/check_bounding_boxes.py new file mode 100755 index 0000000..7443660 --- /dev/null +++ b/skills/pdf/scripts/check_bounding_boxes.py @@ -0,0 +1,70 @@ +from dataclasses import dataclass +import json +import sys + + +# Script to check that the `fields.json` file that Claude creates when analyzing PDFs +# does not have overlapping bounding boxes. See forms.md. + + +@dataclass +class RectAndField: + rect: list[float] + rect_type: str + field: dict + + +# Returns a list of messages that are printed to stdout for Claude to read. +def get_bounding_box_messages(fields_json_stream) -> list[str]: + messages = [] + fields = json.load(fields_json_stream) + messages.append(f"Read {len(fields['form_fields'])} fields") + + def rects_intersect(r1, r2): + disjoint_horizontal = r1[0] >= r2[2] or r1[2] <= r2[0] + disjoint_vertical = r1[1] >= r2[3] or r1[3] <= r2[1] + return not (disjoint_horizontal or disjoint_vertical) + + rects_and_fields = [] + for f in fields["form_fields"]: + rects_and_fields.append(RectAndField(f["label_bounding_box"], "label", f)) + rects_and_fields.append(RectAndField(f["entry_bounding_box"], "entry", f)) + + has_error = False + for i, ri in enumerate(rects_and_fields): + # This is O(N^2); we can optimize if it becomes a problem. + for j in range(i + 1, len(rects_and_fields)): + rj = rects_and_fields[j] + if ri.field["page_number"] == rj.field["page_number"] and rects_intersect(ri.rect, rj.rect): + has_error = True + if ri.field is rj.field: + messages.append(f"FAILURE: intersection between label and entry bounding boxes for `{ri.field['description']}` ({ri.rect}, {rj.rect})") + else: + messages.append(f"FAILURE: intersection between {ri.rect_type} bounding box for `{ri.field['description']}` ({ri.rect}) and {rj.rect_type} bounding box for `{rj.field['description']}` ({rj.rect})") + if len(messages) >= 20: + messages.append("Aborting further checks; fix bounding boxes and try again") + return messages + if ri.rect_type == "entry": + if "entry_text" in ri.field: + font_size = ri.field["entry_text"].get("font_size", 14) + entry_height = ri.rect[3] - ri.rect[1] + if entry_height < font_size: + has_error = True + messages.append(f"FAILURE: entry bounding box height ({entry_height}) for `{ri.field['description']}` is too short for the text content (font size: {font_size}). Increase the box height or decrease the font size.") + if len(messages) >= 20: + messages.append("Aborting further checks; fix bounding boxes and try again") + return messages + + if not has_error: + messages.append("SUCCESS: All bounding boxes are valid") + return messages + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage: check_bounding_boxes.py [fields.json]") + sys.exit(1) + # Input file should be in the `fields.json` format described in forms.md. + with open(sys.argv[1]) as f: + messages = get_bounding_box_messages(f) + for msg in messages: + print(msg) diff --git a/skills/pdf/scripts/check_bounding_boxes_test.py b/skills/pdf/scripts/check_bounding_boxes_test.py new file mode 100755 index 0000000..1dbb463 --- /dev/null +++ b/skills/pdf/scripts/check_bounding_boxes_test.py @@ -0,0 +1,226 @@ +import unittest +import json +import io +from check_bounding_boxes import get_bounding_box_messages + + +# Currently this is not run automatically in CI; it's just for documentation and manual checking. +class TestGetBoundingBoxMessages(unittest.TestCase): + + def create_json_stream(self, data): + """Helper to create a JSON stream from data""" + return io.StringIO(json.dumps(data)) + + def test_no_intersections(self): + """Test case with no bounding box intersections""" + data = { + "form_fields": [ + { + "description": "Name", + "page_number": 1, + "label_bounding_box": [10, 10, 50, 30], + "entry_bounding_box": [60, 10, 150, 30] + }, + { + "description": "Email", + "page_number": 1, + "label_bounding_box": [10, 40, 50, 60], + "entry_bounding_box": [60, 40, 150, 60] + } + ] + } + + stream = self.create_json_stream(data) + messages = get_bounding_box_messages(stream) + self.assertTrue(any("SUCCESS" in msg for msg in messages)) + self.assertFalse(any("FAILURE" in msg for msg in messages)) + + def test_label_entry_intersection_same_field(self): + """Test intersection between label and entry of the same field""" + data = { + "form_fields": [ + { + "description": "Name", + "page_number": 1, + "label_bounding_box": [10, 10, 60, 30], + "entry_bounding_box": [50, 10, 150, 30] # Overlaps with label + } + ] + } + + stream = self.create_json_stream(data) + messages = get_bounding_box_messages(stream) + self.assertTrue(any("FAILURE" in msg and "intersection" in msg for msg in messages)) + self.assertFalse(any("SUCCESS" in msg for msg in messages)) + + def test_intersection_between_different_fields(self): + """Test intersection between bounding boxes of different fields""" + data = { + "form_fields": [ + { + "description": "Name", + "page_number": 1, + "label_bounding_box": [10, 10, 50, 30], + "entry_bounding_box": [60, 10, 150, 30] + }, + { + "description": "Email", + "page_number": 1, + "label_bounding_box": [40, 20, 80, 40], # Overlaps with Name's boxes + "entry_bounding_box": [160, 10, 250, 30] + } + ] + } + + stream = self.create_json_stream(data) + messages = get_bounding_box_messages(stream) + self.assertTrue(any("FAILURE" in msg and "intersection" in msg for msg in messages)) + self.assertFalse(any("SUCCESS" in msg for msg in messages)) + + def test_different_pages_no_intersection(self): + """Test that boxes on different pages don't count as intersecting""" + data = { + "form_fields": [ + { + "description": "Name", + "page_number": 1, + "label_bounding_box": [10, 10, 50, 30], + "entry_bounding_box": [60, 10, 150, 30] + }, + { + "description": "Email", + "page_number": 2, + "label_bounding_box": [10, 10, 50, 30], # Same coordinates but different page + "entry_bounding_box": [60, 10, 150, 30] + } + ] + } + + stream = self.create_json_stream(data) + messages = get_bounding_box_messages(stream) + self.assertTrue(any("SUCCESS" in msg for msg in messages)) + self.assertFalse(any("FAILURE" in msg for msg in messages)) + + def test_entry_height_too_small(self): + """Test that entry box height is checked against font size""" + data = { + "form_fields": [ + { + "description": "Name", + "page_number": 1, + "label_bounding_box": [10, 10, 50, 30], + "entry_bounding_box": [60, 10, 150, 20], # Height is 10 + "entry_text": { + "font_size": 14 # Font size larger than height + } + } + ] + } + + stream = self.create_json_stream(data) + messages = get_bounding_box_messages(stream) + self.assertTrue(any("FAILURE" in msg and "height" in msg for msg in messages)) + self.assertFalse(any("SUCCESS" in msg for msg in messages)) + + def test_entry_height_adequate(self): + """Test that adequate entry box height passes""" + data = { + "form_fields": [ + { + "description": "Name", + "page_number": 1, + "label_bounding_box": [10, 10, 50, 30], + "entry_bounding_box": [60, 10, 150, 30], # Height is 20 + "entry_text": { + "font_size": 14 # Font size smaller than height + } + } + ] + } + + stream = self.create_json_stream(data) + messages = get_bounding_box_messages(stream) + self.assertTrue(any("SUCCESS" in msg for msg in messages)) + self.assertFalse(any("FAILURE" in msg for msg in messages)) + + def test_default_font_size(self): + """Test that default font size is used when not specified""" + data = { + "form_fields": [ + { + "description": "Name", + "page_number": 1, + "label_bounding_box": [10, 10, 50, 30], + "entry_bounding_box": [60, 10, 150, 20], # Height is 10 + "entry_text": {} # No font_size specified, should use default 14 + } + ] + } + + stream = self.create_json_stream(data) + messages = get_bounding_box_messages(stream) + self.assertTrue(any("FAILURE" in msg and "height" in msg for msg in messages)) + self.assertFalse(any("SUCCESS" in msg for msg in messages)) + + def test_no_entry_text(self): + """Test that missing entry_text doesn't cause height check""" + data = { + "form_fields": [ + { + "description": "Name", + "page_number": 1, + "label_bounding_box": [10, 10, 50, 30], + "entry_bounding_box": [60, 10, 150, 20] # Small height but no entry_text + } + ] + } + + stream = self.create_json_stream(data) + messages = get_bounding_box_messages(stream) + self.assertTrue(any("SUCCESS" in msg for msg in messages)) + self.assertFalse(any("FAILURE" in msg for msg in messages)) + + def test_multiple_errors_limit(self): + """Test that error messages are limited to prevent excessive output""" + fields = [] + # Create many overlapping fields + for i in range(25): + fields.append({ + "description": f"Field{i}", + "page_number": 1, + "label_bounding_box": [10, 10, 50, 30], # All overlap + "entry_bounding_box": [20, 15, 60, 35] # All overlap + }) + + data = {"form_fields": fields} + + stream = self.create_json_stream(data) + messages = get_bounding_box_messages(stream) + # Should abort after ~20 messages + self.assertTrue(any("Aborting" in msg for msg in messages)) + # Should have some FAILURE messages but not hundreds + failure_count = sum(1 for msg in messages if "FAILURE" in msg) + self.assertGreater(failure_count, 0) + self.assertLess(len(messages), 30) # Should be limited + + def test_edge_touching_boxes(self): + """Test that boxes touching at edges don't count as intersecting""" + data = { + "form_fields": [ + { + "description": "Name", + "page_number": 1, + "label_bounding_box": [10, 10, 50, 30], + "entry_bounding_box": [50, 10, 150, 30] # Touches at x=50 + } + ] + } + + stream = self.create_json_stream(data) + messages = get_bounding_box_messages(stream) + self.assertTrue(any("SUCCESS" in msg for msg in messages)) + self.assertFalse(any("FAILURE" in msg for msg in messages)) + + +if __name__ == '__main__': + unittest.main() diff --git a/skills/pdf/scripts/check_fillable_fields.py b/skills/pdf/scripts/check_fillable_fields.py new file mode 100755 index 0000000..dc43d18 --- /dev/null +++ b/skills/pdf/scripts/check_fillable_fields.py @@ -0,0 +1,12 @@ +import sys +from pypdf import PdfReader + + +# Script for Claude to run to determine whether a PDF has fillable form fields. See forms.md. + + +reader = PdfReader(sys.argv[1]) +if (reader.get_fields()): + print("This PDF has fillable form fields") +else: + print("This PDF does not have fillable form fields; you will need to visually determine where to enter data") diff --git a/skills/pdf/scripts/convert_pdf_to_images.py b/skills/pdf/scripts/convert_pdf_to_images.py new file mode 100755 index 0000000..f8a4ec5 --- /dev/null +++ b/skills/pdf/scripts/convert_pdf_to_images.py @@ -0,0 +1,35 @@ +import os +import sys + +from pdf2image import convert_from_path + + +# Converts each page of a PDF to a PNG image. + + +def convert(pdf_path, output_dir, max_dim=1000): + images = convert_from_path(pdf_path, dpi=200) + + for i, image in enumerate(images): + # Scale image if needed to keep width/height under `max_dim` + width, height = image.size + if width > max_dim or height > max_dim: + scale_factor = min(max_dim / width, max_dim / height) + new_width = int(width * scale_factor) + new_height = int(height * scale_factor) + image = image.resize((new_width, new_height)) + + image_path = os.path.join(output_dir, f"page_{i+1}.png") + image.save(image_path) + print(f"Saved page {i+1} as {image_path} (size: {image.size})") + + print(f"Converted {len(images)} pages to PNG images") + + +if __name__ == "__main__": + if len(sys.argv) != 3: + print("Usage: convert_pdf_to_images.py [input pdf] [output directory]") + sys.exit(1) + pdf_path = sys.argv[1] + output_directory = sys.argv[2] + convert(pdf_path, output_directory) diff --git a/skills/pdf/scripts/create_validation_image.py b/skills/pdf/scripts/create_validation_image.py new file mode 100755 index 0000000..4913f8f --- /dev/null +++ b/skills/pdf/scripts/create_validation_image.py @@ -0,0 +1,41 @@ +import json +import sys + +from PIL import Image, ImageDraw + + +# Creates "validation" images with rectangles for the bounding box information that +# Claude creates when determining where to add text annotations in PDFs. See forms.md. + + +def create_validation_image(page_number, fields_json_path, input_path, output_path): + # Input file should be in the `fields.json` format described in forms.md. + with open(fields_json_path, 'r') as f: + data = json.load(f) + + img = Image.open(input_path) + draw = ImageDraw.Draw(img) + num_boxes = 0 + + for field in data["form_fields"]: + if field["page_number"] == page_number: + entry_box = field['entry_bounding_box'] + label_box = field['label_bounding_box'] + # Draw red rectangle over entry bounding box and blue rectangle over the label. + draw.rectangle(entry_box, outline='red', width=2) + draw.rectangle(label_box, outline='blue', width=2) + num_boxes += 2 + + img.save(output_path) + print(f"Created validation image at {output_path} with {num_boxes} bounding boxes") + + +if __name__ == "__main__": + if len(sys.argv) != 5: + print("Usage: create_validation_image.py [page number] [fields.json file] [input image path] [output image path]") + sys.exit(1) + page_number = int(sys.argv[1]) + fields_json_path = sys.argv[2] + input_image_path = sys.argv[3] + output_image_path = sys.argv[4] + create_validation_image(page_number, fields_json_path, input_image_path, output_image_path) diff --git a/skills/pdf/scripts/extract_form_field_info.py b/skills/pdf/scripts/extract_form_field_info.py new file mode 100755 index 0000000..f42a2df --- /dev/null +++ b/skills/pdf/scripts/extract_form_field_info.py @@ -0,0 +1,152 @@ +import json +import sys + +from pypdf import PdfReader + + +# Extracts data for the fillable form fields in a PDF and outputs JSON that +# Claude uses to fill the fields. See forms.md. + + +# This matches the format used by PdfReader `get_fields` and `update_page_form_field_values` methods. +def get_full_annotation_field_id(annotation): + components = [] + while annotation: + field_name = annotation.get('/T') + if field_name: + components.append(field_name) + annotation = annotation.get('/Parent') + return ".".join(reversed(components)) if components else None + + +def make_field_dict(field, field_id): + field_dict = {"field_id": field_id} + ft = field.get('/FT') + if ft == "/Tx": + field_dict["type"] = "text" + elif ft == "/Btn": + field_dict["type"] = "checkbox" # radio groups handled separately + states = field.get("/_States_", []) + if len(states) == 2: + # "/Off" seems to always be the unchecked value, as suggested by + # https://opensource.adobe.com/dc-acrobat-sdk-docs/standards/pdfstandards/pdf/PDF32000_2008.pdf#page=448 + # It can be either first or second in the "/_States_" list. + if "/Off" in states: + field_dict["checked_value"] = states[0] if states[0] != "/Off" else states[1] + field_dict["unchecked_value"] = "/Off" + else: + print(f"Unexpected state values for checkbox `${field_id}`. Its checked and unchecked values may not be correct; if you're trying to check it, visually verify the results.") + field_dict["checked_value"] = states[0] + field_dict["unchecked_value"] = states[1] + elif ft == "/Ch": + field_dict["type"] = "choice" + states = field.get("/_States_", []) + field_dict["choice_options"] = [{ + "value": state[0], + "text": state[1], + } for state in states] + else: + field_dict["type"] = f"unknown ({ft})" + return field_dict + + +# Returns a list of fillable PDF fields: +# [ +# { +# "field_id": "name", +# "page": 1, +# "type": ("text", "checkbox", "radio_group", or "choice") +# // Per-type additional fields described in forms.md +# }, +# ] +def get_field_info(reader: PdfReader): + fields = reader.get_fields() + + field_info_by_id = {} + possible_radio_names = set() + + for field_id, field in fields.items(): + # Skip if this is a container field with children, except that it might be + # a parent group for radio button options. + if field.get("/Kids"): + if field.get("/FT") == "/Btn": + possible_radio_names.add(field_id) + continue + field_info_by_id[field_id] = make_field_dict(field, field_id) + + # Bounding rects are stored in annotations in page objects. + + # Radio button options have a separate annotation for each choice; + # all choices have the same field name. + # See https://westhealth.github.io/exploring-fillable-forms-with-pdfrw.html + radio_fields_by_id = {} + + for page_index, page in enumerate(reader.pages): + annotations = page.get('/Annots', []) + for ann in annotations: + field_id = get_full_annotation_field_id(ann) + if field_id in field_info_by_id: + field_info_by_id[field_id]["page"] = page_index + 1 + field_info_by_id[field_id]["rect"] = ann.get('/Rect') + elif field_id in possible_radio_names: + try: + # ann['/AP']['/N'] should have two items. One of them is '/Off', + # the other is the active value. + on_values = [v for v in ann["/AP"]["/N"] if v != "/Off"] + except KeyError: + continue + if len(on_values) == 1: + rect = ann.get("/Rect") + if field_id not in radio_fields_by_id: + radio_fields_by_id[field_id] = { + "field_id": field_id, + "type": "radio_group", + "page": page_index + 1, + "radio_options": [], + } + # Note: at least on macOS 15.7, Preview.app doesn't show selected + # radio buttons correctly. (It does if you remove the leading slash + # from the value, but that causes them not to appear correctly in + # Chrome/Firefox/Acrobat/etc). + radio_fields_by_id[field_id]["radio_options"].append({ + "value": on_values[0], + "rect": rect, + }) + + # Some PDFs have form field definitions without corresponding annotations, + # so we can't tell where they are. Ignore these fields for now. + fields_with_location = [] + for field_info in field_info_by_id.values(): + if "page" in field_info: + fields_with_location.append(field_info) + else: + print(f"Unable to determine location for field id: {field_info.get('field_id')}, ignoring") + + # Sort by page number, then Y position (flipped in PDF coordinate system), then X. + def sort_key(f): + if "radio_options" in f: + rect = f["radio_options"][0]["rect"] or [0, 0, 0, 0] + else: + rect = f.get("rect") or [0, 0, 0, 0] + adjusted_position = [-rect[1], rect[0]] + return [f.get("page"), adjusted_position] + + sorted_fields = fields_with_location + list(radio_fields_by_id.values()) + sorted_fields.sort(key=sort_key) + + return sorted_fields + + +def write_field_info(pdf_path: str, json_output_path: str): + reader = PdfReader(pdf_path) + field_info = get_field_info(reader) + with open(json_output_path, "w") as f: + json.dump(field_info, f, indent=2) + print(f"Wrote {len(field_info)} fields to {json_output_path}") + + +if __name__ == "__main__": + if len(sys.argv) != 3: + print("Usage: extract_form_field_info.py [input pdf] [output json]") + sys.exit(1) + write_field_info(sys.argv[1], sys.argv[2]) diff --git a/skills/pdf/scripts/fill_fillable_fields.py b/skills/pdf/scripts/fill_fillable_fields.py new file mode 100755 index 0000000..ac35753 --- /dev/null +++ b/skills/pdf/scripts/fill_fillable_fields.py @@ -0,0 +1,114 @@ +import json +import sys + +from pypdf import PdfReader, PdfWriter + +from extract_form_field_info import get_field_info + + +# Fills fillable form fields in a PDF. See forms.md. + + +def fill_pdf_fields(input_pdf_path: str, fields_json_path: str, output_pdf_path: str): + with open(fields_json_path) as f: + fields = json.load(f) + # Group by page number. + fields_by_page = {} + for field in fields: + if "value" in field: + field_id = field["field_id"] + page = field["page"] + if page not in fields_by_page: + fields_by_page[page] = {} + fields_by_page[page][field_id] = field["value"] + + reader = PdfReader(input_pdf_path) + + has_error = False + field_info = get_field_info(reader) + fields_by_ids = {f["field_id"]: f for f in field_info} + for field in fields: + existing_field = fields_by_ids.get(field["field_id"]) + if not existing_field: + has_error = True + print(f"ERROR: `{field['field_id']}` is not a valid field ID") + elif field["page"] != existing_field["page"]: + has_error = True + print(f"ERROR: Incorrect page number for `{field['field_id']}` (got {field['page']}, expected {existing_field['page']})") + else: + if "value" in field: + err = validation_error_for_field_value(existing_field, field["value"]) + if err: + print(err) + has_error = True + if has_error: + sys.exit(1) + + writer = PdfWriter(clone_from=reader) + for page, field_values in fields_by_page.items(): + writer.update_page_form_field_values(writer.pages[page - 1], field_values, auto_regenerate=False) + + # This seems to be necessary for many PDF viewers to format the form values correctly. + # It may cause the viewer to show a "save changes" dialog even if the user doesn't make any changes. + writer.set_need_appearances_writer(True) + + with open(output_pdf_path, "wb") as f: + writer.write(f) + + +def validation_error_for_field_value(field_info, field_value): + field_type = field_info["type"] + field_id = field_info["field_id"] + if field_type == "checkbox": + checked_val = field_info["checked_value"] + unchecked_val = field_info["unchecked_value"] + if field_value != checked_val and field_value != unchecked_val: + return f'ERROR: Invalid value "{field_value}" for checkbox field "{field_id}". The checked value is "{checked_val}" and the unchecked value is "{unchecked_val}"' + elif field_type == "radio_group": + option_values = [opt["value"] for opt in field_info["radio_options"]] + if field_value not in option_values: + return f'ERROR: Invalid value "{field_value}" for radio group field "{field_id}". Valid values are: {option_values}' + elif field_type == "choice": + choice_values = [opt["value"] for opt in field_info["choice_options"]] + if field_value not in choice_values: + return f'ERROR: Invalid value "{field_value}" for choice field "{field_id}". Valid values are: {choice_values}' + return None + + +# pypdf (at least version 5.7.0) has a bug when setting the value for a selection list field. +# In _writer.py around line 966: +# +# if field.get(FA.FT, "/Tx") == "/Ch" and field_flags & FA.FfBits.Combo == 0: +# txt = "\n".join(annotation.get_inherited(FA.Opt, [])) +# +# The problem is that for selection lists, `get_inherited` returns a list of two-element lists like +# [["value1", "Text 1"], ["value2", "Text 2"], ...] +# This causes `join` to throw a TypeError because it expects an iterable of strings. +# The horrible workaround is to patch `get_inherited` to return a list of the value strings. +# We call the original method and adjust the return value only if the argument to `get_inherited` +# is `FA.Opt` and if the return value is a list of two-element lists. +def monkeypatch_pydpf_method(): + from pypdf.generic import DictionaryObject + from pypdf.constants import FieldDictionaryAttributes + + original_get_inherited = DictionaryObject.get_inherited + + def patched_get_inherited(self, key: str, default = None): + result = original_get_inherited(self, key, default) + if key == FieldDictionaryAttributes.Opt: + if isinstance(result, list) and all(isinstance(v, list) and len(v) == 2 for v in result): + result = [r[0] for r in result] + return result + + DictionaryObject.get_inherited = patched_get_inherited + + +if __name__ == "__main__": + if len(sys.argv) != 4: + print("Usage: fill_fillable_fields.py [input pdf] [field_values.json] [output pdf]") + sys.exit(1) + monkeypatch_pydpf_method() + input_pdf = sys.argv[1] + fields_json = sys.argv[2] + output_pdf = sys.argv[3] + fill_pdf_fields(input_pdf, fields_json, output_pdf) diff --git a/skills/pdf/scripts/fill_pdf_form_with_annotations.py b/skills/pdf/scripts/fill_pdf_form_with_annotations.py new file mode 100755 index 0000000..f980531 --- /dev/null +++ b/skills/pdf/scripts/fill_pdf_form_with_annotations.py @@ -0,0 +1,108 @@ +import json +import sys + +from pypdf import PdfReader, PdfWriter +from pypdf.annotations import FreeText + + +# Fills a PDF by adding text annotations defined in `fields.json`. See forms.md. + + +def transform_coordinates(bbox, image_width, image_height, pdf_width, pdf_height): + """Transform bounding box from image coordinates to PDF coordinates""" + # Image coordinates: origin at top-left, y increases downward + # PDF coordinates: origin at bottom-left, y increases upward + x_scale = pdf_width / image_width + y_scale = pdf_height / image_height + + left = bbox[0] * x_scale + right = bbox[2] * x_scale + + # Flip Y coordinates for PDF + top = pdf_height - (bbox[1] * y_scale) + bottom = pdf_height - (bbox[3] * y_scale) + + return left, bottom, right, top + + +def fill_pdf_form(input_pdf_path, fields_json_path, output_pdf_path): + """Fill the PDF form with data from fields.json""" + + # `fields.json` format described in forms.md. + with open(fields_json_path, "r") as f: + fields_data = json.load(f) + + # Open the PDF + reader = PdfReader(input_pdf_path) + writer = PdfWriter() + + # Copy all pages to writer + writer.append(reader) + + # Get PDF dimensions for each page + pdf_dimensions = {} + for i, page in enumerate(reader.pages): + mediabox = page.mediabox + pdf_dimensions[i + 1] = [mediabox.width, mediabox.height] + + # Process each form field + annotations = [] + for field in fields_data["form_fields"]: + page_num = field["page_number"] + + # Get page dimensions and transform coordinates. + page_info = next(p for p in fields_data["pages"] if p["page_number"] == page_num) + image_width = page_info["image_width"] + image_height = page_info["image_height"] + pdf_width, pdf_height = pdf_dimensions[page_num] + + transformed_entry_box = transform_coordinates( + field["entry_bounding_box"], + image_width, image_height, + pdf_width, pdf_height + ) + + # Skip empty fields + if "entry_text" not in field or "text" not in field["entry_text"]: + continue + entry_text = field["entry_text"] + text = entry_text["text"] + if not text: + continue + + font_name = entry_text.get("font", "Arial") + font_size = str(entry_text.get("font_size", 14)) + "pt" + font_color = entry_text.get("font_color", "000000") + + # Font size/color seems to not work reliably across viewers: + # https://github.com/py-pdf/pypdf/issues/2084 + annotation = FreeText( + text=text, + rect=transformed_entry_box, + font=font_name, + font_size=font_size, + font_color=font_color, + border_color=None, + background_color=None, + ) + annotations.append(annotation) + # page_number is 0-based for pypdf + writer.add_annotation(page_number=page_num - 1, annotation=annotation) + + # Save the filled PDF + with open(output_pdf_path, "wb") as output: + writer.write(output) + + print(f"Successfully filled PDF form and saved to {output_pdf_path}") + print(f"Added {len(annotations)} text annotations") + + +if __name__ == "__main__": + if len(sys.argv) != 4: + print("Usage: fill_pdf_form_with_annotations.py [input pdf] [fields.json] [output pdf]") + sys.exit(1) + input_pdf = sys.argv[1] + fields_json = sys.argv[2] + output_pdf = sys.argv[3] + + fill_pdf_form(input_pdf, fields_json, output_pdf) \ No newline at end of file diff --git a/skills/pptx/LICENSE.txt b/skills/pptx/LICENSE.txt new file mode 100644 index 0000000..c55ab42 --- /dev/null +++ b/skills/pptx/LICENSE.txt @@ -0,0 +1,30 @@ +© 2025 Anthropic, PBC. All rights reserved. + +LICENSE: Use of these materials (including all code, prompts, assets, files, +and other components of this Skill) is governed by your agreement with +Anthropic regarding use of Anthropic's services. If no separate agreement +exists, use is governed by Anthropic's Consumer Terms of Service or +Commercial Terms of Service, as applicable: +https://www.anthropic.com/legal/consumer-terms +https://www.anthropic.com/legal/commercial-terms +Your applicable agreement is referred to as the "Agreement." "Services" are +as defined in the Agreement. + +ADDITIONAL RESTRICTIONS: Notwithstanding anything in the Agreement to the +contrary, users may not: + +- Extract these materials from the Services or retain copies of these + materials outside the Services +- Reproduce or copy these materials, except for temporary copies created + automatically during authorized use of the Services +- Create derivative works based on these materials +- Distribute, sublicense, or transfer these materials to any third party +- Make, offer to sell, sell, or import any inventions embodied in these + materials +- Reverse engineer, decompile, or disassemble these materials + +The receipt, viewing, or possession of these materials does not convey or +imply any license or right beyond those expressly granted above. + +Anthropic retains all right, title, and interest in these materials, +including all copyrights, patents, and other intellectual property rights. diff --git a/skills/pptx/SKILL.md b/skills/pptx/SKILL.md new file mode 100644 index 0000000..5370fb0 --- /dev/null +++ b/skills/pptx/SKILL.md @@ -0,0 +1,493 @@ +--- +name: pptx +description: "Presentation creation, editing, and analysis. When Claude needs to work with presentations (.pptx files) for: (1) Creating new presentations, (2) Modifying or editing content, (3) Working with layouts, (4) Adding comments or speaker notes, or any other presentation tasks" +triggers: + - "powerpoint" + - "presentation" + - "pptx" + - "slides" + - ".pptx" + - "create presentation" +allowed-tools: Read, Write, Edit, Bash, Glob +version: 1.0.0 +license: Proprietary. LICENSE.txt has complete terms +--- + +# PPTX creation, editing, and analysis + +## Overview + +A user may ask you to create, edit, or analyze the contents of a .pptx file. A .pptx file is essentially a ZIP archive containing XML files and other resources that you can read or edit. You have different tools and workflows available for different tasks. + +## Reading and analyzing content + +### Text extraction +If you just need to read the text contents of a presentation, you should convert the document to markdown: + +```bash +# Convert document to markdown +python -m markitdown path-to-file.pptx +``` + +### Raw XML access +You need raw XML access for: comments, speaker notes, slide layouts, animations, design elements, and complex formatting. For any of these features, you'll need to unpack a presentation and read its raw XML contents. + +#### Unpacking a file +`python ooxml/scripts/unpack.py <office_file> <output_dir>` + +**Note**: The unpack.py script is located at `skills/pptx/ooxml/scripts/unpack.py` relative to the project root. If the script doesn't exist at this path, use `find . -name "unpack.py"` to locate it. + +#### Key file structures +* `ppt/presentation.xml` - Main presentation metadata and slide references +* `ppt/slides/slide{N}.xml` - Individual slide contents (slide1.xml, slide2.xml, etc.) +* `ppt/notesSlides/notesSlide{N}.xml` - Speaker notes for each slide +* `ppt/comments/modernComment_*.xml` - Comments for specific slides +* `ppt/slideLayouts/` - Layout templates for slides +* `ppt/slideMasters/` - Master slide templates +* `ppt/theme/` - Theme and styling information +* `ppt/media/` - Images and other media files + +#### Typography and color extraction +**When given an example design to emulate**: Always analyze the presentation's typography and colors first using the methods below: +1. **Read theme file**: Check `ppt/theme/theme1.xml` for colors (`<a:clrScheme>`) and fonts (`<a:fontScheme>`) +2. **Sample slide content**: Examine `ppt/slides/slide1.xml` for actual font usage (`<a:rPr>`) and colors +3. **Search for patterns**: Use grep to find color (`<a:solidFill>`, `<a:srgbClr>`) and font references across all XML files + +## Creating a new PowerPoint presentation **without a template** + +When creating a new PowerPoint presentation from scratch, use the **html2pptx** workflow to convert HTML slides to PowerPoint with accurate positioning. + +### Design Principles + +**CRITICAL**: Before creating any presentation, analyze the content and choose appropriate design elements: +1. **Consider the subject matter**: What is this presentation about? What tone, industry, or mood does it suggest? +2. **Check for branding**: If the user mentions a company/organization, consider their brand colors and identity +3. **Match palette to content**: Select colors that reflect the subject +4. **State your approach**: Explain your design choices before writing code + +**Requirements**: +- ✅ State your content-informed design approach BEFORE writing code +- ✅ Use web-safe fonts only: Arial, Helvetica, Times New Roman, Georgia, Courier New, Verdana, Tahoma, Trebuchet MS, Impact +- ✅ Create clear visual hierarchy through size, weight, and color +- ✅ Ensure readability: strong contrast, appropriately sized text, clean alignment +- ✅ Be consistent: repeat patterns, spacing, and visual language across slides + +#### Color Palette Selection + +**Choosing colors creatively**: +- **Think beyond defaults**: What colors genuinely match this specific topic? Avoid autopilot choices. +- **Consider multiple angles**: Topic, industry, mood, energy level, target audience, brand identity (if mentioned) +- **Be adventurous**: Try unexpected combinations - a healthcare presentation doesn't have to be green, finance doesn't have to be navy +- **Build your palette**: Pick 3-5 colors that work together (dominant colors + supporting tones + accent) +- **Ensure contrast**: Text must be clearly readable on backgrounds + +**Example color palettes** (use these to spark creativity - choose one, adapt it, or create your own): + +1. **Classic Blue**: Deep navy (#1C2833), slate gray (#2E4053), silver (#AAB7B8), off-white (#F4F6F6) +2. **Teal & Coral**: Teal (#5EA8A7), deep teal (#277884), coral (#FE4447), white (#FFFFFF) +3. **Bold Red**: Red (#C0392B), bright red (#E74C3C), orange (#F39C12), yellow (#F1C40F), green (#2ECC71) +4. **Warm Blush**: Mauve (#A49393), blush (#EED6D3), rose (#E8B4B8), cream (#FAF7F2) +5. **Burgundy Luxury**: Burgundy (#5D1D2E), crimson (#951233), rust (#C15937), gold (#997929) +6. **Deep Purple & Emerald**: Purple (#B165FB), dark blue (#181B24), emerald (#40695B), white (#FFFFFF) +7. **Cream & Forest Green**: Cream (#FFE1C7), forest green (#40695B), white (#FCFCFC) +8. **Pink & Purple**: Pink (#F8275B), coral (#FF574A), rose (#FF737D), purple (#3D2F68) +9. **Lime & Plum**: Lime (#C5DE82), plum (#7C3A5F), coral (#FD8C6E), blue-gray (#98ACB5) +10. **Black & Gold**: Gold (#BF9A4A), black (#000000), cream (#F4F6F6) +11. **Sage & Terracotta**: Sage (#87A96B), terracotta (#E07A5F), cream (#F4F1DE), charcoal (#2C2C2C) +12. **Charcoal & Red**: Charcoal (#292929), red (#E33737), light gray (#CCCBCB) +13. **Vibrant Orange**: Orange (#F96D00), light gray (#F2F2F2), charcoal (#222831) +14. **Forest Green**: Black (#191A19), green (#4E9F3D), dark green (#1E5128), white (#FFFFFF) +15. **Retro Rainbow**: Purple (#722880), pink (#D72D51), orange (#EB5C18), amber (#F08800), gold (#DEB600) +16. **Vintage Earthy**: Mustard (#E3B448), sage (#CBD18F), forest green (#3A6B35), cream (#F4F1DE) +17. **Coastal Rose**: Old rose (#AD7670), beaver (#B49886), eggshell (#F3ECDC), ash gray (#BFD5BE) +18. **Orange & Turquoise**: Light orange (#FC993E), grayish turquoise (#667C6F), white (#FCFCFC) + +#### Visual Details Options + +**Geometric Patterns**: +- Diagonal section dividers instead of horizontal +- Asymmetric column widths (30/70, 40/60, 25/75) +- Rotated text headers at 90° or 270° +- Circular/hexagonal frames for images +- Triangular accent shapes in corners +- Overlapping shapes for depth + +**Border & Frame Treatments**: +- Thick single-color borders (10-20pt) on one side only +- Double-line borders with contrasting colors +- Corner brackets instead of full frames +- L-shaped borders (top+left or bottom+right) +- Underline accents beneath headers (3-5pt thick) + +**Typography Treatments**: +- Extreme size contrast (72pt headlines vs 11pt body) +- All-caps headers with wide letter spacing +- Numbered sections in oversized display type +- Monospace (Courier New) for data/stats/technical content +- Condensed fonts (Arial Narrow) for dense information +- Outlined text for emphasis + +**Chart & Data Styling**: +- Monochrome charts with single accent color for key data +- Horizontal bar charts instead of vertical +- Dot plots instead of bar charts +- Minimal gridlines or none at all +- Data labels directly on elements (no legends) +- Oversized numbers for key metrics + +**Layout Innovations**: +- Full-bleed images with text overlays +- Sidebar column (20-30% width) for navigation/context +- Modular grid systems (3×3, 4×4 blocks) +- Z-pattern or F-pattern content flow +- Floating text boxes over colored shapes +- Magazine-style multi-column layouts + +**Background Treatments**: +- Solid color blocks occupying 40-60% of slide +- Gradient fills (vertical or diagonal only) +- Split backgrounds (two colors, diagonal or vertical) +- Edge-to-edge color bands +- Negative space as a design element + +### Layout Tips +**When creating slides with charts or tables:** +- **Two-column layout (PREFERRED)**: Use a header spanning the full width, then two columns below - text/bullets in one column and the featured content in the other. This provides better balance and makes charts/tables more readable. Use flexbox with unequal column widths (e.g., 40%/60% split) to optimize space for each content type. +- **Full-slide layout**: Let the featured content (chart/table) take up the entire slide for maximum impact and readability +- **NEVER vertically stack**: Do not place charts/tables below text in a single column - this causes poor readability and layout issues + +### Workflow +1. **MANDATORY - READ ENTIRE FILE**: Read [`html2pptx.md`](html2pptx.md) completely from start to finish. **NEVER set any range limits when reading this file.** Read the full file content for detailed syntax, critical formatting rules, and best practices before proceeding with presentation creation. +2. Create an HTML file for each slide with proper dimensions (e.g., 720pt × 405pt for 16:9) + - Use `<p>`, `<h1>`-`<h6>`, `<ul>`, `<ol>` for all text content + - Use `class="placeholder"` for areas where charts/tables will be added (render with gray background for visibility) + - **CRITICAL**: Rasterize gradients and icons as PNG images FIRST using Sharp, then reference in HTML + - **LAYOUT**: For slides with charts/tables/images, use either full-slide layout or two-column layout for better readability +3. Create and run a JavaScript file using the [`html2pptx.js`](scripts/html2pptx.js) library to convert HTML slides to PowerPoint and save the presentation + - Use the `html2pptx()` function to process each HTML file + - Add charts and tables to placeholder areas using PptxGenJS API + - Save the presentation using `pptx.writeFile()` +4. **Visual validation**: Generate thumbnails and inspect for layout issues + - Create thumbnail grid: `python scripts/thumbnail.py output.pptx workspace/thumbnails --cols 4` + - Read and carefully examine the thumbnail image for: + - **Text cutoff**: Text being cut off by header bars, shapes, or slide edges + - **Text overlap**: Text overlapping with other text or shapes + - **Positioning issues**: Content too close to slide boundaries or other elements + - **Contrast issues**: Insufficient contrast between text and backgrounds + - If issues found, adjust HTML margins/spacing/colors and regenerate the presentation + - Repeat until all slides are visually correct + +## Editing an existing PowerPoint presentation + +When edit slides in an existing PowerPoint presentation, you need to work with the raw Office Open XML (OOXML) format. This involves unpacking the .pptx file, editing the XML content, and repacking it. + +### Workflow +1. **MANDATORY - READ ENTIRE FILE**: Read [`ooxml.md`](ooxml.md) (~500 lines) completely from start to finish. **NEVER set any range limits when reading this file.** Read the full file content for detailed guidance on OOXML structure and editing workflows before any presentation editing. +2. Unpack the presentation: `python ooxml/scripts/unpack.py <office_file> <output_dir>` +3. Edit the XML files (primarily `ppt/slides/slide{N}.xml` and related files) +4. **CRITICAL**: Validate immediately after each edit and fix any validation errors before proceeding: `python ooxml/scripts/validate.py <dir> --original <file>` +5. Pack the final presentation: `python ooxml/scripts/pack.py <input_directory> <office_file>` + +## Creating a new PowerPoint presentation **using a template** + +When you need to create a presentation that follows an existing template's design, you'll need to duplicate and re-arrange template slides before then replacing placeholder context. + +### Workflow +1. **Extract template text AND create visual thumbnail grid**: + * Extract text: `python -m markitdown template.pptx > template-content.md` + * Read `template-content.md`: Read the entire file to understand the contents of the template presentation. **NEVER set any range limits when reading this file.** + * Create thumbnail grids: `python scripts/thumbnail.py template.pptx` + * See [Creating Thumbnail Grids](#creating-thumbnail-grids) section for more details + +2. **Analyze template and save inventory to a file**: + * **Visual Analysis**: Review thumbnail grid(s) to understand slide layouts, design patterns, and visual structure + * Create and save a template inventory file at `template-inventory.md` containing: + ```markdown + # Template Inventory Analysis + **Total Slides: [count]** + **IMPORTANT: Slides are 0-indexed (first slide = 0, last slide = count-1)** + + ## [Category Name] + - Slide 0: [Layout code if available] - Description/purpose + - Slide 1: [Layout code] - Description/purpose + - Slide 2: [Layout code] - Description/purpose + [... EVERY slide must be listed individually with its index ...] + ``` + * **Using the thumbnail grid**: Reference the visual thumbnails to identify: + - Layout patterns (title slides, content layouts, section dividers) + - Image placeholder locations and counts + - Design consistency across slide groups + - Visual hierarchy and structure + * This inventory file is REQUIRED for selecting appropriate templates in the next step + +3. **Create presentation outline based on template inventory**: + * Review available templates from step 2. + * Choose an intro or title template for the first slide. This should be one of the first templates. + * Choose safe, text-based layouts for the other slides. + * **CRITICAL: Match layout structure to actual content**: + - Single-column layouts: Use for unified narrative or single topic + - Two-column layouts: Use ONLY when you have exactly 2 distinct items/concepts + - Three-column layouts: Use ONLY when you have exactly 3 distinct items/concepts + - Image + text layouts: Use ONLY when you have actual images to insert + - Quote layouts: Use ONLY for actual quotes from people (with attribution), never for emphasis + - Never use layouts with more placeholders than you have content + - If you have 2 items, don't force them into a 3-column layout + - If you have 4+ items, consider breaking into multiple slides or using a list format + * Count your actual content pieces BEFORE selecting the layout + * Verify each placeholder in the chosen layout will be filled with meaningful content + * Select one option representing the **best** layout for each content section. + * Save `outline.md` with content AND template mapping that leverages available designs + * Example template mapping: + ``` + # Template slides to use (0-based indexing) + # WARNING: Verify indices are within range! Template with 73 slides has indices 0-72 + # Mapping: slide numbers from outline -> template slide indices + template_mapping = [ + 0, # Use slide 0 (Title/Cover) + 34, # Use slide 34 (B1: Title and body) + 34, # Use slide 34 again (duplicate for second B1) + 50, # Use slide 50 (E1: Quote) + 54, # Use slide 54 (F2: Closing + Text) + ] + ``` + +4. **Duplicate, reorder, and delete slides using `rearrange.py`**: + * Use the `scripts/rearrange.py` script to create a new presentation with slides in the desired order: + ```bash + python scripts/rearrange.py template.pptx working.pptx 0,34,34,50,52 + ``` + * The script handles duplicating repeated slides, deleting unused slides, and reordering automatically + * Slide indices are 0-based (first slide is 0, second is 1, etc.) + * The same slide index can appear multiple times to duplicate that slide + +5. **Extract ALL text using the `inventory.py` script**: + * **Run inventory extraction**: + ```bash + python scripts/inventory.py working.pptx text-inventory.json + ``` + * **Read text-inventory.json**: Read the entire text-inventory.json file to understand all shapes and their properties. **NEVER set any range limits when reading this file.** + + * The inventory JSON structure: + ```json + { + "slide-0": { + "shape-0": { + "placeholder_type": "TITLE", // or null for non-placeholders + "left": 1.5, // position in inches + "top": 2.0, + "width": 7.5, + "height": 1.2, + "paragraphs": [ + { + "text": "Paragraph text", + // Optional properties (only included when non-default): + "bullet": true, // explicit bullet detected + "level": 0, // only included when bullet is true + "alignment": "CENTER", // CENTER, RIGHT (not LEFT) + "space_before": 10.0, // space before paragraph in points + "space_after": 6.0, // space after paragraph in points + "line_spacing": 22.4, // line spacing in points + "font_name": "Arial", // from first run + "font_size": 14.0, // in points + "bold": true, + "italic": false, + "underline": false, + "color": "FF0000" // RGB color + } + ] + } + } + } + ``` + + * Key features: + - **Slides**: Named as "slide-0", "slide-1", etc. + - **Shapes**: Ordered by visual position (top-to-bottom, left-to-right) as "shape-0", "shape-1", etc. + - **Placeholder types**: TITLE, CENTER_TITLE, SUBTITLE, BODY, OBJECT, or null + - **Default font size**: `default_font_size` in points extracted from layout placeholders (when available) + - **Slide numbers are filtered**: Shapes with SLIDE_NUMBER placeholder type are automatically excluded from inventory + - **Bullets**: When `bullet: true`, `level` is always included (even if 0) + - **Spacing**: `space_before`, `space_after`, and `line_spacing` in points (only included when set) + - **Colors**: `color` for RGB (e.g., "FF0000"), `theme_color` for theme colors (e.g., "DARK_1") + - **Properties**: Only non-default values are included in the output + +6. **Generate replacement text and save the data to a JSON file** + Based on the text inventory from the previous step: + - **CRITICAL**: First verify which shapes exist in the inventory - only reference shapes that are actually present + - **VALIDATION**: The replace.py script will validate that all shapes in your replacement JSON exist in the inventory + - If you reference a non-existent shape, you'll get an error showing available shapes + - If you reference a non-existent slide, you'll get an error indicating the slide doesn't exist + - All validation errors are shown at once before the script exits + - **IMPORTANT**: The replace.py script uses inventory.py internally to identify ALL text shapes + - **AUTOMATIC CLEARING**: ALL text shapes from the inventory will be cleared unless you provide "paragraphs" for them + - Add a "paragraphs" field to shapes that need content (not "replacement_paragraphs") + - Shapes without "paragraphs" in the replacement JSON will have their text cleared automatically + - Paragraphs with bullets will be automatically left aligned. Don't set the `alignment` property on when `"bullet": true` + - Generate appropriate replacement content for placeholder text + - Use shape size to determine appropriate content length + - **CRITICAL**: Include paragraph properties from the original inventory - don't just provide text + - **IMPORTANT**: When bullet: true, do NOT include bullet symbols (•, -, *) in text - they're added automatically + - **ESSENTIAL FORMATTING RULES**: + - Headers/titles should typically have `"bold": true` + - List items should have `"bullet": true, "level": 0` (level is required when bullet is true) + - Preserve any alignment properties (e.g., `"alignment": "CENTER"` for centered text) + - Include font properties when different from default (e.g., `"font_size": 14.0`, `"font_name": "Lora"`) + - Colors: Use `"color": "FF0000"` for RGB or `"theme_color": "DARK_1"` for theme colors + - The replacement script expects **properly formatted paragraphs**, not just text strings + - **Overlapping shapes**: Prefer shapes with larger default_font_size or more appropriate placeholder_type + - Save the updated inventory with replacements to `replacement-text.json` + - **WARNING**: Different template layouts have different shape counts - always check the actual inventory before creating replacements + + Example paragraphs field showing proper formatting: + ```json + "paragraphs": [ + { + "text": "New presentation title text", + "alignment": "CENTER", + "bold": true + }, + { + "text": "Section Header", + "bold": true + }, + { + "text": "First bullet point without bullet symbol", + "bullet": true, + "level": 0 + }, + { + "text": "Red colored text", + "color": "FF0000" + }, + { + "text": "Theme colored text", + "theme_color": "DARK_1" + }, + { + "text": "Regular paragraph text without special formatting" + } + ] + ``` + + **Shapes not listed in the replacement JSON are automatically cleared**: + ```json + { + "slide-0": { + "shape-0": { + "paragraphs": [...] // This shape gets new text + } + // shape-1 and shape-2 from inventory will be cleared automatically + } + } + ``` + + **Common formatting patterns for presentations**: + - Title slides: Bold text, sometimes centered + - Section headers within slides: Bold text + - Bullet lists: Each item needs `"bullet": true, "level": 0` + - Body text: Usually no special properties needed + - Quotes: May have special alignment or font properties + +7. **Apply replacements using the `replace.py` script** + ```bash + python scripts/replace.py working.pptx replacement-text.json output.pptx + ``` + + The script will: + - First extract the inventory of ALL text shapes using functions from inventory.py + - Validate that all shapes in the replacement JSON exist in the inventory + - Clear text from ALL shapes identified in the inventory + - Apply new text only to shapes with "paragraphs" defined in the replacement JSON + - Preserve formatting by applying paragraph properties from the JSON + - Handle bullets, alignment, font properties, and colors automatically + - Save the updated presentation + + Example validation errors: + ``` + ERROR: Invalid shapes in replacement JSON: + - Shape 'shape-99' not found on 'slide-0'. Available shapes: shape-0, shape-1, shape-4 + - Slide 'slide-999' not found in inventory + ``` + + ``` + ERROR: Replacement text made overflow worse in these shapes: + - slide-0/shape-2: overflow worsened by 1.25" (was 0.00", now 1.25") + ``` + +## Creating Thumbnail Grids + +To create visual thumbnail grids of PowerPoint slides for quick analysis and reference: + +```bash +python scripts/thumbnail.py template.pptx [output_prefix] +``` + +**Features**: +- Creates: `thumbnails.jpg` (or `thumbnails-1.jpg`, `thumbnails-2.jpg`, etc. for large decks) +- Default: 5 columns, max 30 slides per grid (5×6) +- Custom prefix: `python scripts/thumbnail.py template.pptx my-grid` + - Note: The output prefix should include the path if you want output in a specific directory (e.g., `workspace/my-grid`) +- Adjust columns: `--cols 4` (range: 3-6, affects slides per grid) +- Grid limits: 3 cols = 12 slides/grid, 4 cols = 20, 5 cols = 30, 6 cols = 42 +- Slides are zero-indexed (Slide 0, Slide 1, etc.) + +**Use cases**: +- Template analysis: Quickly understand slide layouts and design patterns +- Content review: Visual overview of entire presentation +- Navigation reference: Find specific slides by their visual appearance +- Quality check: Verify all slides are properly formatted + +**Examples**: +```bash +# Basic usage +python scripts/thumbnail.py presentation.pptx + +# Combine options: custom name, columns +python scripts/thumbnail.py template.pptx analysis --cols 4 +``` + +## Converting Slides to Images + +To visually analyze PowerPoint slides, convert them to images using a two-step process: + +1. **Convert PPTX to PDF**: + ```bash + soffice --headless --convert-to pdf template.pptx + ``` + +2. **Convert PDF pages to JPEG images**: + ```bash + pdftoppm -jpeg -r 150 template.pdf slide + ``` + This creates files like `slide-1.jpg`, `slide-2.jpg`, etc. + +Options: +- `-r 150`: Sets resolution to 150 DPI (adjust for quality/size balance) +- `-jpeg`: Output JPEG format (use `-png` for PNG if preferred) +- `-f N`: First page to convert (e.g., `-f 2` starts from page 2) +- `-l N`: Last page to convert (e.g., `-l 5` stops at page 5) +- `slide`: Prefix for output files + +Example for specific range: +```bash +pdftoppm -jpeg -r 150 -f 2 -l 5 template.pdf slide # Converts only pages 2-5 +``` + +## Code Style Guidelines +**IMPORTANT**: When generating code for PPTX operations: +- Write concise code +- Avoid verbose variable names and redundant operations +- Avoid unnecessary print statements + +## Dependencies + +Required dependencies (should already be installed): + +- **markitdown**: `pip install "markitdown[pptx]"` (for text extraction from presentations) +- **pptxgenjs**: `npm install -g pptxgenjs` (for creating presentations via html2pptx) +- **playwright**: `npm install -g playwright` (for HTML rendering in html2pptx) +- **react-icons**: `npm install -g react-icons react react-dom` (for icons) +- **sharp**: `npm install -g sharp` (for SVG rasterization and image processing) +- **LibreOffice**: `sudo apt-get install libreoffice` (for PDF conversion) +- **Poppler**: `sudo apt-get install poppler-utils` (for pdftoppm to convert PDF to images) +- **defusedxml**: `pip install defusedxml` (for secure XML parsing) \ No newline at end of file diff --git a/skills/pptx/html2pptx.md b/skills/pptx/html2pptx.md new file mode 100644 index 0000000..106adf7 --- /dev/null +++ b/skills/pptx/html2pptx.md @@ -0,0 +1,625 @@ +# HTML to PowerPoint Guide + +Convert HTML slides to PowerPoint presentations with accurate positioning using the `html2pptx.js` library. + +## Table of Contents + +1. [Creating HTML Slides](#creating-html-slides) +2. [Using the html2pptx Library](#using-the-html2pptx-library) +3. [Using PptxGenJS](#using-pptxgenjs) + +--- + +## Creating HTML Slides + +Every HTML slide must include proper body dimensions: + +### Layout Dimensions + +- **16:9** (default): `width: 720pt; height: 405pt` +- **4:3**: `width: 720pt; height: 540pt` +- **16:10**: `width: 720pt; height: 450pt` + +### Supported Elements + +- `<p>`, `<h1>`-`<h6>` - Text with styling +- `<ul>`, `<ol>` - Lists (never use manual bullets •, -, *) +- `<b>`, `<strong>` - Bold text (inline formatting) +- `<i>`, `<em>` - Italic text (inline formatting) +- `<u>` - Underlined text (inline formatting) +- `<span>` - Inline formatting with CSS styles (bold, italic, underline, color) +- `<br>` - Line breaks +- `<div>` with bg/border - Becomes shape +- `<img>` - Images +- `class="placeholder"` - Reserved space for charts (returns `{ id, x, y, w, h }`) + +### Critical Text Rules + +**ALL text MUST be inside `<p>`, `<h1>`-`<h6>`, `<ul>`, or `<ol>` tags:** +- ✅ Correct: `<div><p>Text here</p></div>` +- ❌ Wrong: `<div>Text here</div>` - **Text will NOT appear in PowerPoint** +- ❌ Wrong: `<span>Text</span>` - **Text will NOT appear in PowerPoint** +- Text in `<div>` or `<span>` without a text tag will be silently ignored + +**NEVER use manual bullet symbols (•, -, *, etc.)** - Use `<ul>` or `<ol>` lists instead + +**ONLY use web-safe fonts that are universally available:** +- ✅ Web-safe fonts: `Arial`, `Helvetica`, `Times New Roman`, `Georgia`, `Courier New`, `Verdana`, `Tahoma`, `Trebuchet MS`, `Impact`, `Comic Sans MS` +- ❌ Wrong: `'Segoe UI'`, `'SF Pro'`, `'Roboto'`, custom fonts - **Might cause rendering issues** + +### Styling + +- Use `display: flex` on body to prevent margin collapse from breaking overflow validation +- Use `margin` for spacing (padding included in size) +- Inline formatting: Use `<b>`, `<i>`, `<u>` tags OR `<span>` with CSS styles + - `<span>` supports: `font-weight: bold`, `font-style: italic`, `text-decoration: underline`, `color: #rrggbb` + - `<span>` does NOT support: `margin`, `padding` (not supported in PowerPoint text runs) + - Example: `<span style="font-weight: bold; color: #667eea;">Bold blue text</span>` +- Flexbox works - positions calculated from rendered layout +- Use hex colors with `#` prefix in CSS +- **Text alignment**: Use CSS `text-align` (`center`, `right`, etc.) when needed as a hint to PptxGenJS for text formatting if text lengths are slightly off + +### Shape Styling (DIV elements only) + +**IMPORTANT: Backgrounds, borders, and shadows only work on `<div>` elements, NOT on text elements (`<p>`, `<h1>`-`<h6>`, `<ul>`, `<ol>`)** + +- **Backgrounds**: CSS `background` or `background-color` on `<div>` elements only + - Example: `<div style="background: #f0f0f0;">` - Creates a shape with background +- **Borders**: CSS `border` on `<div>` elements converts to PowerPoint shape borders + - Supports uniform borders: `border: 2px solid #333333` + - Supports partial borders: `border-left`, `border-right`, `border-top`, `border-bottom` (rendered as line shapes) + - Example: `<div style="border-left: 8pt solid #E76F51;">` +- **Border radius**: CSS `border-radius` on `<div>` elements for rounded corners + - `border-radius: 50%` or higher creates circular shape + - Percentages <50% calculated relative to shape's smaller dimension + - Supports px and pt units (e.g., `border-radius: 8pt;`, `border-radius: 12px;`) + - Example: `<div style="border-radius: 25%;">` on 100x200px box = 25% of 100px = 25px radius +- **Box shadows**: CSS `box-shadow` on `<div>` elements converts to PowerPoint shadows + - Supports outer shadows only (inset shadows are ignored to prevent corruption) + - Example: `<div style="box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.3);">` + - Note: Inset/inner shadows are not supported by PowerPoint and will be skipped + +### Icons & Gradients + +- **CRITICAL: Never use CSS gradients (`linear-gradient`, `radial-gradient`)** - They don't convert to PowerPoint +- **ALWAYS create gradient/icon PNGs FIRST using Sharp, then reference in HTML** +- For gradients: Rasterize SVG to PNG background images +- For icons: Rasterize react-icons SVG to PNG images +- All visual effects must be pre-rendered as raster images before HTML rendering + +**Rasterizing Icons with Sharp:** + +```javascript +const React = require('react'); +const ReactDOMServer = require('react-dom/server'); +const sharp = require('sharp'); +const { FaHome } = require('react-icons/fa'); + +async function rasterizeIconPng(IconComponent, color, size = "256", filename) { + const svgString = ReactDOMServer.renderToStaticMarkup( + React.createElement(IconComponent, { color: `#${color}`, size: size }) + ); + + // Convert SVG to PNG using Sharp + await sharp(Buffer.from(svgString)) + .png() + .toFile(filename); + + return filename; +} + +// Usage: Rasterize icon before using in HTML +const iconPath = await rasterizeIconPng(FaHome, "4472c4", "256", "home-icon.png"); +// Then reference in HTML: <img src="home-icon.png" style="width: 40pt; height: 40pt;"> +``` + +**Rasterizing Gradients with Sharp:** + +```javascript +const sharp = require('sharp'); + +async function createGradientBackground(filename) { + const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="562.5"> + <defs> + <linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="100%"> + <stop offset="0%" style="stop-color:#COLOR1"/> + <stop offset="100%" style="stop-color:#COLOR2"/> + </linearGradient> + </defs> + <rect width="100%" height="100%" fill="url(#g)"/> + </svg>`; + + await sharp(Buffer.from(svg)) + .png() + .toFile(filename); + + return filename; +} + +// Usage: Create gradient background before HTML +const bgPath = await createGradientBackground("gradient-bg.png"); +// Then in HTML: <body style="background-image: url('gradient-bg.png');"> +``` + +### Example + +```html +<!DOCTYPE html> +<html> +<head> +<style> +html { background: #ffffff; } +body { + width: 720pt; height: 405pt; margin: 0; padding: 0; + background: #f5f5f5; font-family: Arial, sans-serif; + display: flex; +} +.content { margin: 30pt; padding: 40pt; background: #ffffff; border-radius: 8pt; } +h1 { color: #2d3748; font-size: 32pt; } +.box { + background: #70ad47; padding: 20pt; border: 3px solid #5a8f37; + border-radius: 12pt; box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.25); +} +</style> +</head> +<body> +<div class="content"> + <h1>Recipe Title</h1> + <ul> + <li><b>Item:</b> Description</li> + </ul> + <p>Text with <b>bold</b>, <i>italic</i>, <u>underline</u>.</p> + <div id="chart" class="placeholder" style="width: 350pt; height: 200pt;"></div> + + <!-- Text MUST be in <p> tags --> + <div class="box"> + <p>5</p> + </div> +</div> +</body> +</html> +``` + +## Using the html2pptx Library + +### Dependencies + +These libraries have been globally installed and are available to use: +- `pptxgenjs` +- `playwright` +- `sharp` + +### Basic Usage + +```javascript +const pptxgen = require('pptxgenjs'); +const html2pptx = require('./html2pptx'); + +const pptx = new pptxgen(); +pptx.layout = 'LAYOUT_16x9'; // Must match HTML body dimensions + +const { slide, placeholders } = await html2pptx('slide1.html', pptx); + +// Add chart to placeholder area +if (placeholders.length > 0) { + slide.addChart(pptx.charts.LINE, chartData, placeholders[0]); +} + +await pptx.writeFile('output.pptx'); +``` + +### API Reference + +#### Function Signature +```javascript +await html2pptx(htmlFile, pres, options) +``` + +#### Parameters +- `htmlFile` (string): Path to HTML file (absolute or relative) +- `pres` (pptxgen): PptxGenJS presentation instance with layout already set +- `options` (object, optional): + - `tmpDir` (string): Temporary directory for generated files (default: `process.env.TMPDIR || '/tmp'`) + - `slide` (object): Existing slide to reuse (default: creates new slide) + +#### Returns +```javascript +{ + slide: pptxgenSlide, // The created/updated slide + placeholders: [ // Array of placeholder positions + { id: string, x: number, y: number, w: number, h: number }, + ... + ] +} +``` + +### Validation + +The library automatically validates and collects all errors before throwing: + +1. **HTML dimensions must match presentation layout** - Reports dimension mismatches +2. **Content must not overflow body** - Reports overflow with exact measurements +3. **CSS gradients** - Reports unsupported gradient usage +4. **Text element styling** - Reports backgrounds/borders/shadows on text elements (only allowed on divs) + +**All validation errors are collected and reported together** in a single error message, allowing you to fix all issues at once instead of one at a time. + +### Working with Placeholders + +```javascript +const { slide, placeholders } = await html2pptx('slide.html', pptx); + +// Use first placeholder +slide.addChart(pptx.charts.BAR, data, placeholders[0]); + +// Find by ID +const chartArea = placeholders.find(p => p.id === 'chart-area'); +slide.addChart(pptx.charts.LINE, data, chartArea); +``` + +### Complete Example + +```javascript +const pptxgen = require('pptxgenjs'); +const html2pptx = require('./html2pptx'); + +async function createPresentation() { + const pptx = new pptxgen(); + pptx.layout = 'LAYOUT_16x9'; + pptx.author = 'Your Name'; + pptx.title = 'My Presentation'; + + // Slide 1: Title + const { slide: slide1 } = await html2pptx('slides/title.html', pptx); + + // Slide 2: Content with chart + const { slide: slide2, placeholders } = await html2pptx('slides/data.html', pptx); + + const chartData = [{ + name: 'Sales', + labels: ['Q1', 'Q2', 'Q3', 'Q4'], + values: [4500, 5500, 6200, 7100] + }]; + + slide2.addChart(pptx.charts.BAR, chartData, { + ...placeholders[0], + showTitle: true, + title: 'Quarterly Sales', + showCatAxisTitle: true, + catAxisTitle: 'Quarter', + showValAxisTitle: true, + valAxisTitle: 'Sales ($000s)' + }); + + // Save + await pptx.writeFile({ fileName: 'presentation.pptx' }); + console.log('Presentation created successfully!'); +} + +createPresentation().catch(console.error); +``` + +## Using PptxGenJS + +After converting HTML to slides with `html2pptx`, you'll use PptxGenJS to add dynamic content like charts, images, and additional elements. + +### ⚠️ Critical Rules + +#### Colors +- **NEVER use `#` prefix** with hex colors in PptxGenJS - causes file corruption +- ✅ Correct: `color: "FF0000"`, `fill: { color: "0066CC" }` +- ❌ Wrong: `color: "#FF0000"` (breaks document) + +### Adding Images + +Always calculate aspect ratios from actual image dimensions: + +```javascript +// Get image dimensions: identify image.png | grep -o '[0-9]* x [0-9]*' +const imgWidth = 1860, imgHeight = 1519; // From actual file +const aspectRatio = imgWidth / imgHeight; + +const h = 3; // Max height +const w = h * aspectRatio; +const x = (10 - w) / 2; // Center on 16:9 slide + +slide.addImage({ path: "chart.png", x, y: 1.5, w, h }); +``` + +### Adding Text + +```javascript +// Rich text with formatting +slide.addText([ + { text: "Bold ", options: { bold: true } }, + { text: "Italic ", options: { italic: true } }, + { text: "Normal" } +], { + x: 1, y: 2, w: 8, h: 1 +}); +``` + +### Adding Shapes + +```javascript +// Rectangle +slide.addShape(pptx.shapes.RECTANGLE, { + x: 1, y: 1, w: 3, h: 2, + fill: { color: "4472C4" }, + line: { color: "000000", width: 2 } +}); + +// Circle +slide.addShape(pptx.shapes.OVAL, { + x: 5, y: 1, w: 2, h: 2, + fill: { color: "ED7D31" } +}); + +// Rounded rectangle +slide.addShape(pptx.shapes.ROUNDED_RECTANGLE, { + x: 1, y: 4, w: 3, h: 1.5, + fill: { color: "70AD47" }, + rectRadius: 0.2 +}); +``` + +### Adding Charts + +**Required for most charts:** Axis labels using `catAxisTitle` (category) and `valAxisTitle` (value). + +**Chart Data Format:** +- Use **single series with all labels** for simple bar/line charts +- Each series creates a separate legend entry +- Labels array defines X-axis values + +**Time Series Data - Choose Correct Granularity:** +- **< 30 days**: Use daily grouping (e.g., "10-01", "10-02") - avoid monthly aggregation that creates single-point charts +- **30-365 days**: Use monthly grouping (e.g., "2024-01", "2024-02") +- **> 365 days**: Use yearly grouping (e.g., "2023", "2024") +- **Validate**: Charts with only 1 data point likely indicate incorrect aggregation for the time period + +```javascript +const { slide, placeholders } = await html2pptx('slide.html', pptx); + +// CORRECT: Single series with all labels +slide.addChart(pptx.charts.BAR, [{ + name: "Sales 2024", + labels: ["Q1", "Q2", "Q3", "Q4"], + values: [4500, 5500, 6200, 7100] +}], { + ...placeholders[0], // Use placeholder position + barDir: 'col', // 'col' = vertical bars, 'bar' = horizontal + showTitle: true, + title: 'Quarterly Sales', + showLegend: false, // No legend needed for single series + // Required axis labels + showCatAxisTitle: true, + catAxisTitle: 'Quarter', + showValAxisTitle: true, + valAxisTitle: 'Sales ($000s)', + // Optional: Control scaling (adjust min based on data range for better visualization) + valAxisMaxVal: 8000, + valAxisMinVal: 0, // Use 0 for counts/amounts; for clustered data (e.g., 4500-7100), consider starting closer to min value + valAxisMajorUnit: 2000, // Control y-axis label spacing to prevent crowding + catAxisLabelRotate: 45, // Rotate labels if crowded + dataLabelPosition: 'outEnd', + dataLabelColor: '000000', + // Use single color for single-series charts + chartColors: ["4472C4"] // All bars same color +}); +``` + +#### Scatter Chart + +**IMPORTANT**: Scatter chart data format is unusual - first series contains X-axis values, subsequent series contain Y-values: + +```javascript +// Prepare data +const data1 = [{ x: 10, y: 20 }, { x: 15, y: 25 }, { x: 20, y: 30 }]; +const data2 = [{ x: 12, y: 18 }, { x: 18, y: 22 }]; + +const allXValues = [...data1.map(d => d.x), ...data2.map(d => d.x)]; + +slide.addChart(pptx.charts.SCATTER, [ + { name: 'X-Axis', values: allXValues }, // First series = X values + { name: 'Series 1', values: data1.map(d => d.y) }, // Y values only + { name: 'Series 2', values: data2.map(d => d.y) } // Y values only +], { + x: 1, y: 1, w: 8, h: 4, + lineSize: 0, // 0 = no connecting lines + lineDataSymbol: 'circle', + lineDataSymbolSize: 6, + showCatAxisTitle: true, + catAxisTitle: 'X Axis', + showValAxisTitle: true, + valAxisTitle: 'Y Axis', + chartColors: ["4472C4", "ED7D31"] +}); +``` + +#### Line Chart + +```javascript +slide.addChart(pptx.charts.LINE, [{ + name: "Temperature", + labels: ["Jan", "Feb", "Mar", "Apr"], + values: [32, 35, 42, 55] +}], { + x: 1, y: 1, w: 8, h: 4, + lineSize: 4, + lineSmooth: true, + // Required axis labels + showCatAxisTitle: true, + catAxisTitle: 'Month', + showValAxisTitle: true, + valAxisTitle: 'Temperature (°F)', + // Optional: Y-axis range (set min based on data range for better visualization) + valAxisMinVal: 0, // For ranges starting at 0 (counts, percentages, etc.) + valAxisMaxVal: 60, + valAxisMajorUnit: 20, // Control y-axis label spacing to prevent crowding (e.g., 10, 20, 25) + // valAxisMinVal: 30, // PREFERRED: For data clustered in a range (e.g., 32-55 or ratings 3-5), start axis closer to min value to show variation + // Optional: Chart colors + chartColors: ["4472C4", "ED7D31", "A5A5A5"] +}); +``` + +#### Pie Chart (No Axis Labels Required) + +**CRITICAL**: Pie charts require a **single data series** with all categories in the `labels` array and corresponding values in the `values` array. + +```javascript +slide.addChart(pptx.charts.PIE, [{ + name: "Market Share", + labels: ["Product A", "Product B", "Other"], // All categories in one array + values: [35, 45, 20] // All values in one array +}], { + x: 2, y: 1, w: 6, h: 4, + showPercent: true, + showLegend: true, + legendPos: 'r', // right + chartColors: ["4472C4", "ED7D31", "A5A5A5"] +}); +``` + +#### Multiple Data Series + +```javascript +slide.addChart(pptx.charts.LINE, [ + { + name: "Product A", + labels: ["Q1", "Q2", "Q3", "Q4"], + values: [10, 20, 30, 40] + }, + { + name: "Product B", + labels: ["Q1", "Q2", "Q3", "Q4"], + values: [15, 25, 20, 35] + } +], { + x: 1, y: 1, w: 8, h: 4, + showCatAxisTitle: true, + catAxisTitle: 'Quarter', + showValAxisTitle: true, + valAxisTitle: 'Revenue ($M)' +}); +``` + +### Chart Colors + +**CRITICAL**: Use hex colors **without** the `#` prefix - including `#` causes file corruption. + +**Align chart colors with your chosen design palette**, ensuring sufficient contrast and distinctiveness for data visualization. Adjust colors for: +- Strong contrast between adjacent series +- Readability against slide backgrounds +- Accessibility (avoid red-green only combinations) + +```javascript +// Example: Ocean palette-inspired chart colors (adjusted for contrast) +const chartColors = ["16A085", "FF6B9D", "2C3E50", "F39C12", "9B59B6"]; + +// Single-series chart: Use one color for all bars/points +slide.addChart(pptx.charts.BAR, [{ + name: "Sales", + labels: ["Q1", "Q2", "Q3", "Q4"], + values: [4500, 5500, 6200, 7100] +}], { + ...placeholders[0], + chartColors: ["16A085"], // All bars same color + showLegend: false +}); + +// Multi-series chart: Each series gets a different color +slide.addChart(pptx.charts.LINE, [ + { name: "Product A", labels: ["Q1", "Q2", "Q3"], values: [10, 20, 30] }, + { name: "Product B", labels: ["Q1", "Q2", "Q3"], values: [15, 25, 20] } +], { + ...placeholders[0], + chartColors: ["16A085", "FF6B9D"] // One color per series +}); +``` + +### Adding Tables + +Tables can be added with basic or advanced formatting: + +#### Basic Table + +```javascript +slide.addTable([ + ["Header 1", "Header 2", "Header 3"], + ["Row 1, Col 1", "Row 1, Col 2", "Row 1, Col 3"], + ["Row 2, Col 1", "Row 2, Col 2", "Row 2, Col 3"] +], { + x: 0.5, + y: 1, + w: 9, + h: 3, + border: { pt: 1, color: "999999" }, + fill: { color: "F1F1F1" } +}); +``` + +#### Table with Custom Formatting + +```javascript +const tableData = [ + // Header row with custom styling + [ + { text: "Product", options: { fill: { color: "4472C4" }, color: "FFFFFF", bold: true } }, + { text: "Revenue", options: { fill: { color: "4472C4" }, color: "FFFFFF", bold: true } }, + { text: "Growth", options: { fill: { color: "4472C4" }, color: "FFFFFF", bold: true } } + ], + // Data rows + ["Product A", "$50M", "+15%"], + ["Product B", "$35M", "+22%"], + ["Product C", "$28M", "+8%"] +]; + +slide.addTable(tableData, { + x: 1, + y: 1.5, + w: 8, + h: 3, + colW: [3, 2.5, 2.5], // Column widths + rowH: [0.5, 0.6, 0.6, 0.6], // Row heights + border: { pt: 1, color: "CCCCCC" }, + align: "center", + valign: "middle", + fontSize: 14 +}); +``` + +#### Table with Merged Cells + +```javascript +const mergedTableData = [ + [ + { text: "Q1 Results", options: { colspan: 3, fill: { color: "4472C4" }, color: "FFFFFF", bold: true } } + ], + ["Product", "Sales", "Market Share"], + ["Product A", "$25M", "35%"], + ["Product B", "$18M", "25%"] +]; + +slide.addTable(mergedTableData, { + x: 1, + y: 1, + w: 8, + h: 2.5, + colW: [3, 2.5, 2.5], + border: { pt: 1, color: "DDDDDD" } +}); +``` + +### Table Options + +Common table options: +- `x, y, w, h` - Position and size +- `colW` - Array of column widths (in inches) +- `rowH` - Array of row heights (in inches) +- `border` - Border style: `{ pt: 1, color: "999999" }` +- `fill` - Background color (no # prefix) +- `align` - Text alignment: "left", "center", "right" +- `valign` - Vertical alignment: "top", "middle", "bottom" +- `fontSize` - Text size +- `autoPage` - Auto-create new slides if content overflows \ No newline at end of file diff --git a/skills/pptx/ooxml.md b/skills/pptx/ooxml.md new file mode 100644 index 0000000..951b3cf --- /dev/null +++ b/skills/pptx/ooxml.md @@ -0,0 +1,427 @@ +# Office Open XML Technical Reference for PowerPoint + +**Important: Read this entire document before starting.** Critical XML schema rules and formatting requirements are covered throughout. Incorrect implementation can create invalid PPTX files that PowerPoint cannot open. + +## Technical Guidelines + +### Schema Compliance +- **Element ordering in `<p:txBody>`**: `<a:bodyPr>`, `<a:lstStyle>`, `<a:p>` +- **Whitespace**: Add `xml:space='preserve'` to `<a:t>` elements with leading/trailing spaces +- **Unicode**: Escape characters in ASCII content: `"` becomes `“` +- **Images**: Add to `ppt/media/`, reference in slide XML, set dimensions to fit slide bounds +- **Relationships**: Update `ppt/slides/_rels/slideN.xml.rels` for each slide's resources +- **Dirty attribute**: Add `dirty="0"` to `<a:rPr>` and `<a:endParaRPr>` elements to indicate clean state + +## Presentation Structure + +### Basic Slide Structure +```xml +<!-- ppt/slides/slide1.xml --> +<p:sld> + <p:cSld> + <p:spTree> + <p:nvGrpSpPr>...</p:nvGrpSpPr> + <p:grpSpPr>...</p:grpSpPr> + <!-- Shapes go here --> + </p:spTree> + </p:cSld> +</p:sld> +``` + +### Text Box / Shape with Text +```xml +<p:sp> + <p:nvSpPr> + <p:cNvPr id="2" name="Title"/> + <p:cNvSpPr> + <a:spLocks noGrp="1"/> + </p:cNvSpPr> + <p:nvPr> + <p:ph type="ctrTitle"/> + </p:nvPr> + </p:nvSpPr> + <p:spPr> + <a:xfrm> + <a:off x="838200" y="365125"/> + <a:ext cx="7772400" cy="1470025"/> + </a:xfrm> + </p:spPr> + <p:txBody> + <a:bodyPr/> + <a:lstStyle/> + <a:p> + <a:r> + <a:t>Slide Title</a:t> + </a:r> + </a:p> + </p:txBody> +</p:sp> +``` + +### Text Formatting +```xml +<!-- Bold --> +<a:r> + <a:rPr b="1"/> + <a:t>Bold Text</a:t> +</a:r> + +<!-- Italic --> +<a:r> + <a:rPr i="1"/> + <a:t>Italic Text</a:t> +</a:r> + +<!-- Underline --> +<a:r> + <a:rPr u="sng"/> + <a:t>Underlined</a:t> +</a:r> + +<!-- Highlight --> +<a:r> + <a:rPr> + <a:highlight> + <a:srgbClr val="FFFF00"/> + </a:highlight> + </a:rPr> + <a:t>Highlighted Text</a:t> +</a:r> + +<!-- Font and Size --> +<a:r> + <a:rPr sz="2400" typeface="Arial"> + <a:solidFill> + <a:srgbClr val="FF0000"/> + </a:solidFill> + </a:rPr> + <a:t>Colored Arial 24pt</a:t> +</a:r> + +<!-- Complete formatting example --> +<a:r> + <a:rPr lang="en-US" sz="1400" b="1" dirty="0"> + <a:solidFill> + <a:srgbClr val="FAFAFA"/> + </a:solidFill> + </a:rPr> + <a:t>Formatted text</a:t> +</a:r> +``` + +### Lists +```xml +<!-- Bullet list --> +<a:p> + <a:pPr lvl="0"> + <a:buChar char="•"/> + </a:pPr> + <a:r> + <a:t>First bullet point</a:t> + </a:r> +</a:p> + +<!-- Numbered list --> +<a:p> + <a:pPr lvl="0"> + <a:buAutoNum type="arabicPeriod"/> + </a:pPr> + <a:r> + <a:t>First numbered item</a:t> + </a:r> +</a:p> + +<!-- Second level indent --> +<a:p> + <a:pPr lvl="1"> + <a:buChar char="•"/> + </a:pPr> + <a:r> + <a:t>Indented bullet</a:t> + </a:r> +</a:p> +``` + +### Shapes +```xml +<!-- Rectangle --> +<p:sp> + <p:nvSpPr> + <p:cNvPr id="3" name="Rectangle"/> + <p:cNvSpPr/> + <p:nvPr/> + </p:nvSpPr> + <p:spPr> + <a:xfrm> + <a:off x="1000000" y="1000000"/> + <a:ext cx="3000000" cy="2000000"/> + </a:xfrm> + <a:prstGeom prst="rect"> + <a:avLst/> + </a:prstGeom> + <a:solidFill> + <a:srgbClr val="FF0000"/> + </a:solidFill> + <a:ln w="25400"> + <a:solidFill> + <a:srgbClr val="000000"/> + </a:solidFill> + </a:ln> + </p:spPr> +</p:sp> + +<!-- Rounded Rectangle --> +<p:sp> + <p:spPr> + <a:prstGeom prst="roundRect"> + <a:avLst/> + </a:prstGeom> + </p:spPr> +</p:sp> + +<!-- Circle/Ellipse --> +<p:sp> + <p:spPr> + <a:prstGeom prst="ellipse"> + <a:avLst/> + </a:prstGeom> + </p:spPr> +</p:sp> +``` + +### Images +```xml +<p:pic> + <p:nvPicPr> + <p:cNvPr id="4" name="Picture"> + <a:hlinkClick r:id="" action="ppaction://media"/> + </p:cNvPr> + <p:cNvPicPr> + <a:picLocks noChangeAspect="1"/> + </p:cNvPicPr> + <p:nvPr/> + </p:nvPicPr> + <p:blipFill> + <a:blip r:embed="rId2"/> + <a:stretch> + <a:fillRect/> + </a:stretch> + </p:blipFill> + <p:spPr> + <a:xfrm> + <a:off x="1000000" y="1000000"/> + <a:ext cx="3000000" cy="2000000"/> + </a:xfrm> + <a:prstGeom prst="rect"> + <a:avLst/> + </a:prstGeom> + </p:spPr> +</p:pic> +``` + +### Tables +```xml +<p:graphicFrame> + <p:nvGraphicFramePr> + <p:cNvPr id="5" name="Table"/> + <p:cNvGraphicFramePr> + <a:graphicFrameLocks noGrp="1"/> + </p:cNvGraphicFramePr> + <p:nvPr/> + </p:nvGraphicFramePr> + <p:xfrm> + <a:off x="1000000" y="1000000"/> + <a:ext cx="6000000" cy="2000000"/> + </p:xfrm> + <a:graphic> + <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/table"> + <a:tbl> + <a:tblGrid> + <a:gridCol w="3000000"/> + <a:gridCol w="3000000"/> + </a:tblGrid> + <a:tr h="500000"> + <a:tc> + <a:txBody> + <a:bodyPr/> + <a:lstStyle/> + <a:p> + <a:r> + <a:t>Cell 1</a:t> + </a:r> + </a:p> + </a:txBody> + </a:tc> + <a:tc> + <a:txBody> + <a:bodyPr/> + <a:lstStyle/> + <a:p> + <a:r> + <a:t>Cell 2</a:t> + </a:r> + </a:p> + </a:txBody> + </a:tc> + </a:tr> + </a:tbl> + </a:graphicData> + </a:graphic> +</p:graphicFrame> +``` + +### Slide Layouts + +```xml +<!-- Title Slide Layout --> +<p:sp> + <p:nvSpPr> + <p:nvPr> + <p:ph type="ctrTitle"/> + </p:nvPr> + </p:nvSpPr> + <!-- Title content --> +</p:sp> + +<p:sp> + <p:nvSpPr> + <p:nvPr> + <p:ph type="subTitle" idx="1"/> + </p:nvPr> + </p:nvSpPr> + <!-- Subtitle content --> +</p:sp> + +<!-- Content Slide Layout --> +<p:sp> + <p:nvSpPr> + <p:nvPr> + <p:ph type="title"/> + </p:nvPr> + </p:nvSpPr> + <!-- Slide title --> +</p:sp> + +<p:sp> + <p:nvSpPr> + <p:nvPr> + <p:ph type="body" idx="1"/> + </p:nvPr> + </p:nvSpPr> + <!-- Content body --> +</p:sp> +``` + +## File Updates + +When adding content, update these files: + +**`ppt/_rels/presentation.xml.rels`:** +```xml +<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="slides/slide1.xml"/> +<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="slideMasters/slideMaster1.xml"/> +``` + +**`ppt/slides/_rels/slide1.xml.rels`:** +```xml +<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout1.xml"/> +<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="../media/image1.png"/> +``` + +**`[Content_Types].xml`:** +```xml +<Default Extension="png" ContentType="image/png"/> +<Default Extension="jpg" ContentType="image/jpeg"/> +<Override PartName="/ppt/slides/slide1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slide+xml"/> +``` + +**`ppt/presentation.xml`:** +```xml +<p:sldIdLst> + <p:sldId id="256" r:id="rId1"/> + <p:sldId id="257" r:id="rId2"/> +</p:sldIdLst> +``` + +**`docProps/app.xml`:** Update slide count and statistics +```xml +<Slides>2</Slides> +<Paragraphs>10</Paragraphs> +<Words>50</Words> +``` + +## Slide Operations + +### Adding a New Slide +When adding a slide to the end of the presentation: + +1. **Create the slide file** (`ppt/slides/slideN.xml`) +2. **Update `[Content_Types].xml`**: Add Override for the new slide +3. **Update `ppt/_rels/presentation.xml.rels`**: Add relationship for the new slide +4. **Update `ppt/presentation.xml`**: Add slide ID to `<p:sldIdLst>` +5. **Create slide relationships** (`ppt/slides/_rels/slideN.xml.rels`) if needed +6. **Update `docProps/app.xml`**: Increment slide count and update statistics (if present) + +### Duplicating a Slide +1. Copy the source slide XML file with a new name +2. Update all IDs in the new slide to be unique +3. Follow the "Adding a New Slide" steps above +4. **CRITICAL**: Remove or update any notes slide references in `_rels` files +5. Remove references to unused media files + +### Reordering Slides +1. **Update `ppt/presentation.xml`**: Reorder `<p:sldId>` elements in `<p:sldIdLst>` +2. The order of `<p:sldId>` elements determines slide order +3. Keep slide IDs and relationship IDs unchanged + +Example: +```xml +<!-- Original order --> +<p:sldIdLst> + <p:sldId id="256" r:id="rId2"/> + <p:sldId id="257" r:id="rId3"/> + <p:sldId id="258" r:id="rId4"/> +</p:sldIdLst> + +<!-- After moving slide 3 to position 2 --> +<p:sldIdLst> + <p:sldId id="256" r:id="rId2"/> + <p:sldId id="258" r:id="rId4"/> + <p:sldId id="257" r:id="rId3"/> +</p:sldIdLst> +``` + +### Deleting a Slide +1. **Remove from `ppt/presentation.xml`**: Delete the `<p:sldId>` entry +2. **Remove from `ppt/_rels/presentation.xml.rels`**: Delete the relationship +3. **Remove from `[Content_Types].xml`**: Delete the Override entry +4. **Delete files**: Remove `ppt/slides/slideN.xml` and `ppt/slides/_rels/slideN.xml.rels` +5. **Update `docProps/app.xml`**: Decrement slide count and update statistics +6. **Clean up unused media**: Remove orphaned images from `ppt/media/` + +Note: Don't renumber remaining slides - keep their original IDs and filenames. + + +## Common Errors to Avoid + +- **Encodings**: Escape unicode characters in ASCII content: `"` becomes `“` +- **Images**: Add to `ppt/media/` and update relationship files +- **Lists**: Omit bullets from list headers +- **IDs**: Use valid hexadecimal values for UUIDs +- **Themes**: Check all themes in `theme` directory for colors + +## Validation Checklist for Template-Based Presentations + +### Before Packing, Always: +- **Clean unused resources**: Remove unreferenced media, fonts, and notes directories +- **Fix Content_Types.xml**: Declare ALL slides, layouts, and themes present in the package +- **Fix relationship IDs**: + - Remove font embed references if not using embedded fonts +- **Remove broken references**: Check all `_rels` files for references to deleted resources + +### Common Template Duplication Pitfalls: +- Multiple slides referencing the same notes slide after duplication +- Image/media references from template slides that no longer exist +- Font embedding references when fonts aren't included +- Missing slideLayout declarations for layouts 12-25 +- docProps directory may not unpack - this is optional \ No newline at end of file diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd new file mode 100644 index 0000000..6454ef9 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd @@ -0,0 +1,1499 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" + xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + xmlns="http://schemas.openxmlformats.org/drawingml/2006/chart" + xmlns:cdr="http://schemas.openxmlformats.org/drawingml/2006/chartDrawing" + xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/chart" + elementFormDefault="qualified" attributeFormDefault="unqualified" blockDefault="#all"> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + schemaLocation="shared-relationshipReference.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main" + schemaLocation="dml-main.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/chartDrawing" + schemaLocation="dml-chartDrawing.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + schemaLocation="shared-commonSimpleTypes.xsd"/> + <xsd:complexType name="CT_Boolean"> + <xsd:attribute name="val" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_Double"> + <xsd:attribute name="val" type="xsd:double" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_UnsignedInt"> + <xsd:attribute name="val" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_RelId"> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Extension"> + <xsd:sequence> + <xsd:any processContents="lax"/> + </xsd:sequence> + <xsd:attribute name="uri" type="xsd:token"/> + </xsd:complexType> + <xsd:complexType name="CT_ExtensionList"> + <xsd:sequence> + <xsd:element name="ext" type="CT_Extension" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_NumVal"> + <xsd:sequence> + <xsd:element name="v" type="s:ST_Xstring" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="idx" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="formatCode" type="s:ST_Xstring" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_NumData"> + <xsd:sequence> + <xsd:element name="formatCode" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ptCount" type="CT_UnsignedInt" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pt" type="CT_NumVal" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_NumRef"> + <xsd:sequence> + <xsd:element name="f" type="xsd:string" minOccurs="1" maxOccurs="1"/> + <xsd:element name="numCache" type="CT_NumData" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_NumDataSource"> + <xsd:sequence> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="numRef" type="CT_NumRef" minOccurs="1" maxOccurs="1"/> + <xsd:element name="numLit" type="CT_NumData" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_StrVal"> + <xsd:sequence> + <xsd:element name="v" type="s:ST_Xstring" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="idx" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_StrData"> + <xsd:sequence> + <xsd:element name="ptCount" type="CT_UnsignedInt" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pt" type="CT_StrVal" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_StrRef"> + <xsd:sequence> + <xsd:element name="f" type="xsd:string" minOccurs="1" maxOccurs="1"/> + <xsd:element name="strCache" type="CT_StrData" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Tx"> + <xsd:sequence> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="strRef" type="CT_StrRef" minOccurs="1" maxOccurs="1"/> + <xsd:element name="rich" type="a:CT_TextBody" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TextLanguageID"> + <xsd:attribute name="val" type="s:ST_Lang" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Lvl"> + <xsd:sequence> + <xsd:element name="pt" type="CT_StrVal" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_MultiLvlStrData"> + <xsd:sequence> + <xsd:element name="ptCount" type="CT_UnsignedInt" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lvl" type="CT_Lvl" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_MultiLvlStrRef"> + <xsd:sequence> + <xsd:element name="f" type="xsd:string" minOccurs="1" maxOccurs="1"/> + <xsd:element name="multiLvlStrCache" type="CT_MultiLvlStrData" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_AxDataSource"> + <xsd:sequence> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="multiLvlStrRef" type="CT_MultiLvlStrRef" minOccurs="1" maxOccurs="1"/> + <xsd:element name="numRef" type="CT_NumRef" minOccurs="1" maxOccurs="1"/> + <xsd:element name="numLit" type="CT_NumData" minOccurs="1" maxOccurs="1"/> + <xsd:element name="strRef" type="CT_StrRef" minOccurs="1" maxOccurs="1"/> + <xsd:element name="strLit" type="CT_StrData" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SerTx"> + <xsd:sequence> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="strRef" type="CT_StrRef" minOccurs="1" maxOccurs="1"/> + <xsd:element name="v" type="s:ST_Xstring" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_LayoutTarget"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="inner"/> + <xsd:enumeration value="outer"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_LayoutTarget"> + <xsd:attribute name="val" type="ST_LayoutTarget" default="outer"/> + </xsd:complexType> + <xsd:simpleType name="ST_LayoutMode"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="edge"/> + <xsd:enumeration value="factor"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_LayoutMode"> + <xsd:attribute name="val" type="ST_LayoutMode" default="factor"/> + </xsd:complexType> + <xsd:complexType name="CT_ManualLayout"> + <xsd:sequence> + <xsd:element name="layoutTarget" type="CT_LayoutTarget" minOccurs="0" maxOccurs="1"/> + <xsd:element name="xMode" type="CT_LayoutMode" minOccurs="0" maxOccurs="1"/> + <xsd:element name="yMode" type="CT_LayoutMode" minOccurs="0" maxOccurs="1"/> + <xsd:element name="wMode" type="CT_LayoutMode" minOccurs="0" maxOccurs="1"/> + <xsd:element name="hMode" type="CT_LayoutMode" minOccurs="0" maxOccurs="1"/> + <xsd:element name="x" type="CT_Double" minOccurs="0" maxOccurs="1"/> + <xsd:element name="y" type="CT_Double" minOccurs="0" maxOccurs="1"/> + <xsd:element name="w" type="CT_Double" minOccurs="0" maxOccurs="1"/> + <xsd:element name="h" type="CT_Double" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Layout"> + <xsd:sequence> + <xsd:element name="manualLayout" type="CT_ManualLayout" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Title"> + <xsd:sequence> + <xsd:element name="tx" type="CT_Tx" minOccurs="0" maxOccurs="1"/> + <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/> + <xsd:element name="overlay" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_RotX"> + <xsd:restriction base="xsd:byte"> + <xsd:minInclusive value="-90"/> + <xsd:maxInclusive value="90"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_RotX"> + <xsd:attribute name="val" type="ST_RotX" default="0"/> + </xsd:complexType> + <xsd:simpleType name="ST_HPercent"> + <xsd:union memberTypes="ST_HPercentWithSymbol ST_HPercentUShort"/> + </xsd:simpleType> + <xsd:simpleType name="ST_HPercentWithSymbol"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="0*(([5-9])|([1-9][0-9])|([1-4][0-9][0-9])|500)%"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_HPercentUShort"> + <xsd:restriction base="xsd:unsignedShort"> + <xsd:minInclusive value="5"/> + <xsd:maxInclusive value="500"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_HPercent"> + <xsd:attribute name="val" type="ST_HPercent" default="100%"/> + </xsd:complexType> + <xsd:simpleType name="ST_RotY"> + <xsd:restriction base="xsd:unsignedShort"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="360"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_RotY"> + <xsd:attribute name="val" type="ST_RotY" default="0"/> + </xsd:complexType> + <xsd:simpleType name="ST_DepthPercent"> + <xsd:union memberTypes="ST_DepthPercentWithSymbol ST_DepthPercentUShort"/> + </xsd:simpleType> + <xsd:simpleType name="ST_DepthPercentWithSymbol"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="0*(([2-9][0-9])|([1-9][0-9][0-9])|(1[0-9][0-9][0-9])|2000)%"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_DepthPercentUShort"> + <xsd:restriction base="xsd:unsignedShort"> + <xsd:minInclusive value="20"/> + <xsd:maxInclusive value="2000"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_DepthPercent"> + <xsd:attribute name="val" type="ST_DepthPercent" default="100%"/> + </xsd:complexType> + <xsd:simpleType name="ST_Perspective"> + <xsd:restriction base="xsd:unsignedByte"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="240"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Perspective"> + <xsd:attribute name="val" type="ST_Perspective" default="30"/> + </xsd:complexType> + <xsd:complexType name="CT_View3D"> + <xsd:sequence> + <xsd:element name="rotX" type="CT_RotX" minOccurs="0" maxOccurs="1"/> + <xsd:element name="hPercent" type="CT_HPercent" minOccurs="0" maxOccurs="1"/> + <xsd:element name="rotY" type="CT_RotY" minOccurs="0" maxOccurs="1"/> + <xsd:element name="depthPercent" type="CT_DepthPercent" minOccurs="0" maxOccurs="1"/> + <xsd:element name="rAngAx" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="perspective" type="CT_Perspective" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Surface"> + <xsd:sequence> + <xsd:element name="thickness" type="CT_Thickness" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pictureOptions" type="CT_PictureOptions" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_Thickness"> + <xsd:union memberTypes="ST_ThicknessPercent xsd:unsignedInt"/> + </xsd:simpleType> + <xsd:simpleType name="ST_ThicknessPercent"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="([0-9]+)%"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Thickness"> + <xsd:attribute name="val" type="ST_Thickness" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_DTable"> + <xsd:sequence> + <xsd:element name="showHorzBorder" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="showVertBorder" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="showOutline" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="showKeys" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_GapAmount"> + <xsd:union memberTypes="ST_GapAmountPercent ST_GapAmountUShort"/> + </xsd:simpleType> + <xsd:simpleType name="ST_GapAmountPercent"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="0*(([0-9])|([1-9][0-9])|([1-4][0-9][0-9])|500)%"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_GapAmountUShort"> + <xsd:restriction base="xsd:unsignedShort"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="500"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_GapAmount"> + <xsd:attribute name="val" type="ST_GapAmount" default="150%"/> + </xsd:complexType> + <xsd:simpleType name="ST_Overlap"> + <xsd:union memberTypes="ST_OverlapPercent ST_OverlapByte"/> + </xsd:simpleType> + <xsd:simpleType name="ST_OverlapPercent"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="(-?0*(([0-9])|([1-9][0-9])|100))%"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_OverlapByte"> + <xsd:restriction base="xsd:byte"> + <xsd:minInclusive value="-100"/> + <xsd:maxInclusive value="100"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Overlap"> + <xsd:attribute name="val" type="ST_Overlap" default="0%"/> + </xsd:complexType> + <xsd:simpleType name="ST_BubbleScale"> + <xsd:union memberTypes="ST_BubbleScalePercent ST_BubbleScaleUInt"/> + </xsd:simpleType> + <xsd:simpleType name="ST_BubbleScalePercent"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="0*(([0-9])|([1-9][0-9])|([1-2][0-9][0-9])|300)%"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_BubbleScaleUInt"> + <xsd:restriction base="xsd:unsignedInt"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="300"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_BubbleScale"> + <xsd:attribute name="val" type="ST_BubbleScale" default="100%"/> + </xsd:complexType> + <xsd:simpleType name="ST_SizeRepresents"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="area"/> + <xsd:enumeration value="w"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SizeRepresents"> + <xsd:attribute name="val" type="ST_SizeRepresents" default="area"/> + </xsd:complexType> + <xsd:simpleType name="ST_FirstSliceAng"> + <xsd:restriction base="xsd:unsignedShort"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="360"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_FirstSliceAng"> + <xsd:attribute name="val" type="ST_FirstSliceAng" default="0"/> + </xsd:complexType> + <xsd:simpleType name="ST_HoleSize"> + <xsd:union memberTypes="ST_HoleSizePercent ST_HoleSizeUByte"/> + </xsd:simpleType> + <xsd:simpleType name="ST_HoleSizePercent"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="0*([1-9]|([1-8][0-9])|90)%"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_HoleSizeUByte"> + <xsd:restriction base="xsd:unsignedByte"> + <xsd:minInclusive value="1"/> + <xsd:maxInclusive value="90"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_HoleSize"> + <xsd:attribute name="val" type="ST_HoleSize" default="10%"/> + </xsd:complexType> + <xsd:simpleType name="ST_SplitType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="auto"/> + <xsd:enumeration value="cust"/> + <xsd:enumeration value="percent"/> + <xsd:enumeration value="pos"/> + <xsd:enumeration value="val"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SplitType"> + <xsd:attribute name="val" type="ST_SplitType" default="auto"/> + </xsd:complexType> + <xsd:complexType name="CT_CustSplit"> + <xsd:sequence> + <xsd:element name="secondPiePt" type="CT_UnsignedInt" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_SecondPieSize"> + <xsd:union memberTypes="ST_SecondPieSizePercent ST_SecondPieSizeUShort"/> + </xsd:simpleType> + <xsd:simpleType name="ST_SecondPieSizePercent"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="0*(([5-9])|([1-9][0-9])|(1[0-9][0-9])|200)%"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_SecondPieSizeUShort"> + <xsd:restriction base="xsd:unsignedShort"> + <xsd:minInclusive value="5"/> + <xsd:maxInclusive value="200"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SecondPieSize"> + <xsd:attribute name="val" type="ST_SecondPieSize" default="75%"/> + </xsd:complexType> + <xsd:complexType name="CT_NumFmt"> + <xsd:attribute name="formatCode" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="sourceLinked" type="xsd:boolean"/> + </xsd:complexType> + <xsd:simpleType name="ST_LblAlgn"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="l"/> + <xsd:enumeration value="r"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_LblAlgn"> + <xsd:attribute name="val" type="ST_LblAlgn" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_DLblPos"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="bestFit"/> + <xsd:enumeration value="b"/> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="inBase"/> + <xsd:enumeration value="inEnd"/> + <xsd:enumeration value="l"/> + <xsd:enumeration value="outEnd"/> + <xsd:enumeration value="r"/> + <xsd:enumeration value="t"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_DLblPos"> + <xsd:attribute name="val" type="ST_DLblPos" use="required"/> + </xsd:complexType> + <xsd:group name="EG_DLblShared"> + <xsd:sequence> + <xsd:element name="numFmt" type="CT_NumFmt" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dLblPos" type="CT_DLblPos" minOccurs="0" maxOccurs="1"/> + <xsd:element name="showLegendKey" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="showVal" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="showCatName" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="showSerName" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="showPercent" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="showBubbleSize" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="separator" type="xsd:string" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:group> + <xsd:group name="Group_DLbl"> + <xsd:sequence> + <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tx" type="CT_Tx" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_DLblShared" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_DLbl"> + <xsd:sequence> + <xsd:element name="idx" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> + <xsd:choice> + <xsd:element name="delete" type="CT_Boolean" minOccurs="1" maxOccurs="1"/> + <xsd:group ref="Group_DLbl" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="Group_DLbls"> + <xsd:sequence> + <xsd:group ref="EG_DLblShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="showLeaderLines" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="leaderLines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_DLbls"> + <xsd:sequence> + <xsd:element name="dLbl" type="CT_DLbl" minOccurs="0" maxOccurs="unbounded"/> + <xsd:choice> + <xsd:element name="delete" type="CT_Boolean" minOccurs="1" maxOccurs="1"/> + <xsd:group ref="Group_DLbls" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_MarkerStyle"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="circle"/> + <xsd:enumeration value="dash"/> + <xsd:enumeration value="diamond"/> + <xsd:enumeration value="dot"/> + <xsd:enumeration value="none"/> + <xsd:enumeration value="picture"/> + <xsd:enumeration value="plus"/> + <xsd:enumeration value="square"/> + <xsd:enumeration value="star"/> + <xsd:enumeration value="triangle"/> + <xsd:enumeration value="x"/> + <xsd:enumeration value="auto"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_MarkerStyle"> + <xsd:attribute name="val" type="ST_MarkerStyle" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_MarkerSize"> + <xsd:restriction base="xsd:unsignedByte"> + <xsd:minInclusive value="2"/> + <xsd:maxInclusive value="72"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_MarkerSize"> + <xsd:attribute name="val" type="ST_MarkerSize" default="5"/> + </xsd:complexType> + <xsd:complexType name="CT_Marker"> + <xsd:sequence> + <xsd:element name="symbol" type="CT_MarkerStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="size" type="CT_MarkerSize" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DPt"> + <xsd:sequence> + <xsd:element name="idx" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> + <xsd:element name="invertIfNegative" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="marker" type="CT_Marker" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bubble3D" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="explosion" type="CT_UnsignedInt" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pictureOptions" type="CT_PictureOptions" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_TrendlineType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="exp"/> + <xsd:enumeration value="linear"/> + <xsd:enumeration value="log"/> + <xsd:enumeration value="movingAvg"/> + <xsd:enumeration value="poly"/> + <xsd:enumeration value="power"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TrendlineType"> + <xsd:attribute name="val" type="ST_TrendlineType" default="linear"/> + </xsd:complexType> + <xsd:simpleType name="ST_Order"> + <xsd:restriction base="xsd:unsignedByte"> + <xsd:minInclusive value="2"/> + <xsd:maxInclusive value="6"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Order"> + <xsd:attribute name="val" type="ST_Order" default="2"/> + </xsd:complexType> + <xsd:simpleType name="ST_Period"> + <xsd:restriction base="xsd:unsignedInt"> + <xsd:minInclusive value="2"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Period"> + <xsd:attribute name="val" type="ST_Period" default="2"/> + </xsd:complexType> + <xsd:complexType name="CT_TrendlineLbl"> + <xsd:sequence> + <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tx" type="CT_Tx" minOccurs="0" maxOccurs="1"/> + <xsd:element name="numFmt" type="CT_NumFmt" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Trendline"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="trendlineType" type="CT_TrendlineType" minOccurs="1" maxOccurs="1"/> + <xsd:element name="order" type="CT_Order" minOccurs="0" maxOccurs="1"/> + <xsd:element name="period" type="CT_Period" minOccurs="0" maxOccurs="1"/> + <xsd:element name="forward" type="CT_Double" minOccurs="0" maxOccurs="1"/> + <xsd:element name="backward" type="CT_Double" minOccurs="0" maxOccurs="1"/> + <xsd:element name="intercept" type="CT_Double" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dispRSqr" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dispEq" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="trendlineLbl" type="CT_TrendlineLbl" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_ErrDir"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="x"/> + <xsd:enumeration value="y"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_ErrDir"> + <xsd:attribute name="val" type="ST_ErrDir" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_ErrBarType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="both"/> + <xsd:enumeration value="minus"/> + <xsd:enumeration value="plus"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_ErrBarType"> + <xsd:attribute name="val" type="ST_ErrBarType" default="both"/> + </xsd:complexType> + <xsd:simpleType name="ST_ErrValType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="cust"/> + <xsd:enumeration value="fixedVal"/> + <xsd:enumeration value="percentage"/> + <xsd:enumeration value="stdDev"/> + <xsd:enumeration value="stdErr"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_ErrValType"> + <xsd:attribute name="val" type="ST_ErrValType" default="fixedVal"/> + </xsd:complexType> + <xsd:complexType name="CT_ErrBars"> + <xsd:sequence> + <xsd:element name="errDir" type="CT_ErrDir" minOccurs="0" maxOccurs="1"/> + <xsd:element name="errBarType" type="CT_ErrBarType" minOccurs="1" maxOccurs="1"/> + <xsd:element name="errValType" type="CT_ErrValType" minOccurs="1" maxOccurs="1"/> + <xsd:element name="noEndCap" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="plus" type="CT_NumDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="minus" type="CT_NumDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="val" type="CT_Double" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_UpDownBar"> + <xsd:sequence> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_UpDownBars"> + <xsd:sequence> + <xsd:element name="gapWidth" type="CT_GapAmount" minOccurs="0" maxOccurs="1"/> + <xsd:element name="upBars" type="CT_UpDownBar" minOccurs="0" maxOccurs="1"/> + <xsd:element name="downBars" type="CT_UpDownBar" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_SerShared"> + <xsd:sequence> + <xsd:element name="idx" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> + <xsd:element name="order" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> + <xsd:element name="tx" type="CT_SerTx" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_LineSer"> + <xsd:sequence> + <xsd:group ref="EG_SerShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="marker" type="CT_Marker" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dPt" type="CT_DPt" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="trendline" type="CT_Trendline" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="errBars" type="CT_ErrBars" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cat" type="CT_AxDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="val" type="CT_NumDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="smooth" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ScatterSer"> + <xsd:sequence> + <xsd:group ref="EG_SerShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="marker" type="CT_Marker" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dPt" type="CT_DPt" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="trendline" type="CT_Trendline" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="errBars" type="CT_ErrBars" minOccurs="0" maxOccurs="2"/> + <xsd:element name="xVal" type="CT_AxDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="yVal" type="CT_NumDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="smooth" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_RadarSer"> + <xsd:sequence> + <xsd:group ref="EG_SerShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="marker" type="CT_Marker" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dPt" type="CT_DPt" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cat" type="CT_AxDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="val" type="CT_NumDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_BarSer"> + <xsd:sequence> + <xsd:group ref="EG_SerShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="invertIfNegative" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pictureOptions" type="CT_PictureOptions" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dPt" type="CT_DPt" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="trendline" type="CT_Trendline" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="errBars" type="CT_ErrBars" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cat" type="CT_AxDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="val" type="CT_NumDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="shape" type="CT_Shape" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_AreaSer"> + <xsd:sequence> + <xsd:group ref="EG_SerShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="pictureOptions" type="CT_PictureOptions" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dPt" type="CT_DPt" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="trendline" type="CT_Trendline" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="errBars" type="CT_ErrBars" minOccurs="0" maxOccurs="2"/> + <xsd:element name="cat" type="CT_AxDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="val" type="CT_NumDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PieSer"> + <xsd:sequence> + <xsd:group ref="EG_SerShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="explosion" type="CT_UnsignedInt" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dPt" type="CT_DPt" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cat" type="CT_AxDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="val" type="CT_NumDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_BubbleSer"> + <xsd:sequence> + <xsd:group ref="EG_SerShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="invertIfNegative" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dPt" type="CT_DPt" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="trendline" type="CT_Trendline" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="errBars" type="CT_ErrBars" minOccurs="0" maxOccurs="2"/> + <xsd:element name="xVal" type="CT_AxDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="yVal" type="CT_NumDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bubbleSize" type="CT_NumDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bubble3D" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SurfaceSer"> + <xsd:sequence> + <xsd:group ref="EG_SerShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cat" type="CT_AxDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="val" type="CT_NumDataSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_Grouping"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="percentStacked"/> + <xsd:enumeration value="standard"/> + <xsd:enumeration value="stacked"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Grouping"> + <xsd:attribute name="val" type="ST_Grouping" default="standard"/> + </xsd:complexType> + <xsd:complexType name="CT_ChartLines"> + <xsd:sequence> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_LineChartShared"> + <xsd:sequence> + <xsd:element name="grouping" type="CT_Grouping" minOccurs="1" maxOccurs="1"/> + <xsd:element name="varyColors" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ser" type="CT_LineSer" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dropLines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_LineChart"> + <xsd:sequence> + <xsd:group ref="EG_LineChartShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="hiLowLines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> + <xsd:element name="upDownBars" type="CT_UpDownBars" minOccurs="0" maxOccurs="1"/> + <xsd:element name="marker" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="smooth" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="2" maxOccurs="2"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Line3DChart"> + <xsd:sequence> + <xsd:group ref="EG_LineChartShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="gapDepth" type="CT_GapAmount" minOccurs="0" maxOccurs="1"/> + <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="3" maxOccurs="3"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_StockChart"> + <xsd:sequence> + <xsd:element name="ser" type="CT_LineSer" minOccurs="3" maxOccurs="4"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dropLines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> + <xsd:element name="hiLowLines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> + <xsd:element name="upDownBars" type="CT_UpDownBars" minOccurs="0" maxOccurs="1"/> + <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="2" maxOccurs="2"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_ScatterStyle"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="line"/> + <xsd:enumeration value="lineMarker"/> + <xsd:enumeration value="marker"/> + <xsd:enumeration value="smooth"/> + <xsd:enumeration value="smoothMarker"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_ScatterStyle"> + <xsd:attribute name="val" type="ST_ScatterStyle" default="marker"/> + </xsd:complexType> + <xsd:complexType name="CT_ScatterChart"> + <xsd:sequence> + <xsd:element name="scatterStyle" type="CT_ScatterStyle" minOccurs="1" maxOccurs="1"/> + <xsd:element name="varyColors" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ser" type="CT_ScatterSer" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="2" maxOccurs="2"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_RadarStyle"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="standard"/> + <xsd:enumeration value="marker"/> + <xsd:enumeration value="filled"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_RadarStyle"> + <xsd:attribute name="val" type="ST_RadarStyle" default="standard"/> + </xsd:complexType> + <xsd:complexType name="CT_RadarChart"> + <xsd:sequence> + <xsd:element name="radarStyle" type="CT_RadarStyle" minOccurs="1" maxOccurs="1"/> + <xsd:element name="varyColors" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ser" type="CT_RadarSer" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="2" maxOccurs="2"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_BarGrouping"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="percentStacked"/> + <xsd:enumeration value="clustered"/> + <xsd:enumeration value="standard"/> + <xsd:enumeration value="stacked"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_BarGrouping"> + <xsd:attribute name="val" type="ST_BarGrouping" default="clustered"/> + </xsd:complexType> + <xsd:simpleType name="ST_BarDir"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="bar"/> + <xsd:enumeration value="col"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_BarDir"> + <xsd:attribute name="val" type="ST_BarDir" default="col"/> + </xsd:complexType> + <xsd:simpleType name="ST_Shape"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="cone"/> + <xsd:enumeration value="coneToMax"/> + <xsd:enumeration value="box"/> + <xsd:enumeration value="cylinder"/> + <xsd:enumeration value="pyramid"/> + <xsd:enumeration value="pyramidToMax"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Shape"> + <xsd:attribute name="val" type="ST_Shape" default="box"/> + </xsd:complexType> + <xsd:group name="EG_BarChartShared"> + <xsd:sequence> + <xsd:element name="barDir" type="CT_BarDir" minOccurs="1" maxOccurs="1"/> + <xsd:element name="grouping" type="CT_BarGrouping" minOccurs="0" maxOccurs="1"/> + <xsd:element name="varyColors" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ser" type="CT_BarSer" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_BarChart"> + <xsd:sequence> + <xsd:group ref="EG_BarChartShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="gapWidth" type="CT_GapAmount" minOccurs="0" maxOccurs="1"/> + <xsd:element name="overlap" type="CT_Overlap" minOccurs="0" maxOccurs="1"/> + <xsd:element name="serLines" type="CT_ChartLines" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="2" maxOccurs="2"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Bar3DChart"> + <xsd:sequence> + <xsd:group ref="EG_BarChartShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="gapWidth" type="CT_GapAmount" minOccurs="0" maxOccurs="1"/> + <xsd:element name="gapDepth" type="CT_GapAmount" minOccurs="0" maxOccurs="1"/> + <xsd:element name="shape" type="CT_Shape" minOccurs="0" maxOccurs="1"/> + <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="2" maxOccurs="3"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_AreaChartShared"> + <xsd:sequence> + <xsd:element name="grouping" type="CT_Grouping" minOccurs="0" maxOccurs="1"/> + <xsd:element name="varyColors" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ser" type="CT_AreaSer" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dropLines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_AreaChart"> + <xsd:sequence> + <xsd:group ref="EG_AreaChartShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="2" maxOccurs="2"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Area3DChart"> + <xsd:sequence> + <xsd:group ref="EG_AreaChartShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="gapDepth" type="CT_GapAmount" minOccurs="0" maxOccurs="1"/> + <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="2" maxOccurs="3"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_PieChartShared"> + <xsd:sequence> + <xsd:element name="varyColors" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ser" type="CT_PieSer" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_PieChart"> + <xsd:sequence> + <xsd:group ref="EG_PieChartShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="firstSliceAng" type="CT_FirstSliceAng" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Pie3DChart"> + <xsd:sequence> + <xsd:group ref="EG_PieChartShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DoughnutChart"> + <xsd:sequence> + <xsd:group ref="EG_PieChartShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="firstSliceAng" type="CT_FirstSliceAng" minOccurs="0" maxOccurs="1"/> + <xsd:element name="holeSize" type="CT_HoleSize" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_OfPieType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="pie"/> + <xsd:enumeration value="bar"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_OfPieType"> + <xsd:attribute name="val" type="ST_OfPieType" default="pie"/> + </xsd:complexType> + <xsd:complexType name="CT_OfPieChart"> + <xsd:sequence> + <xsd:element name="ofPieType" type="CT_OfPieType" minOccurs="1" maxOccurs="1"/> + <xsd:group ref="EG_PieChartShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="gapWidth" type="CT_GapAmount" minOccurs="0" maxOccurs="1"/> + <xsd:element name="splitType" type="CT_SplitType" minOccurs="0" maxOccurs="1"/> + <xsd:element name="splitPos" type="CT_Double" minOccurs="0" maxOccurs="1"/> + <xsd:element name="custSplit" type="CT_CustSplit" minOccurs="0" maxOccurs="1"/> + <xsd:element name="secondPieSize" type="CT_SecondPieSize" minOccurs="0" maxOccurs="1"/> + <xsd:element name="serLines" type="CT_ChartLines" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_BubbleChart"> + <xsd:sequence> + <xsd:element name="varyColors" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ser" type="CT_BubbleSer" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dLbls" type="CT_DLbls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bubble3D" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bubbleScale" type="CT_BubbleScale" minOccurs="0" maxOccurs="1"/> + <xsd:element name="showNegBubbles" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sizeRepresents" type="CT_SizeRepresents" minOccurs="0" maxOccurs="1"/> + <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="2" maxOccurs="2"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_BandFmt"> + <xsd:sequence> + <xsd:element name="idx" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_BandFmts"> + <xsd:sequence> + <xsd:element name="bandFmt" type="CT_BandFmt" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_SurfaceChartShared"> + <xsd:sequence> + <xsd:element name="wireframe" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ser" type="CT_SurfaceSer" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="bandFmts" type="CT_BandFmts" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_SurfaceChart"> + <xsd:sequence> + <xsd:group ref="EG_SurfaceChartShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="2" maxOccurs="3"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Surface3DChart"> + <xsd:sequence> + <xsd:group ref="EG_SurfaceChartShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="3" maxOccurs="3"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_AxPos"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="b"/> + <xsd:enumeration value="l"/> + <xsd:enumeration value="r"/> + <xsd:enumeration value="t"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_AxPos"> + <xsd:attribute name="val" type="ST_AxPos" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_Crosses"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="autoZero"/> + <xsd:enumeration value="max"/> + <xsd:enumeration value="min"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Crosses"> + <xsd:attribute name="val" type="ST_Crosses" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_CrossBetween"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="between"/> + <xsd:enumeration value="midCat"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_CrossBetween"> + <xsd:attribute name="val" type="ST_CrossBetween" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_TickMark"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="cross"/> + <xsd:enumeration value="in"/> + <xsd:enumeration value="none"/> + <xsd:enumeration value="out"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TickMark"> + <xsd:attribute name="val" type="ST_TickMark" default="cross"/> + </xsd:complexType> + <xsd:simpleType name="ST_TickLblPos"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="high"/> + <xsd:enumeration value="low"/> + <xsd:enumeration value="nextTo"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TickLblPos"> + <xsd:attribute name="val" type="ST_TickLblPos" default="nextTo"/> + </xsd:complexType> + <xsd:simpleType name="ST_Skip"> + <xsd:restriction base="xsd:unsignedInt"> + <xsd:minInclusive value="1"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Skip"> + <xsd:attribute name="val" type="ST_Skip" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_TimeUnit"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="days"/> + <xsd:enumeration value="months"/> + <xsd:enumeration value="years"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TimeUnit"> + <xsd:attribute name="val" type="ST_TimeUnit" default="days"/> + </xsd:complexType> + <xsd:simpleType name="ST_AxisUnit"> + <xsd:restriction base="xsd:double"> + <xsd:minExclusive value="0"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_AxisUnit"> + <xsd:attribute name="val" type="ST_AxisUnit" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_BuiltInUnit"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="hundreds"/> + <xsd:enumeration value="thousands"/> + <xsd:enumeration value="tenThousands"/> + <xsd:enumeration value="hundredThousands"/> + <xsd:enumeration value="millions"/> + <xsd:enumeration value="tenMillions"/> + <xsd:enumeration value="hundredMillions"/> + <xsd:enumeration value="billions"/> + <xsd:enumeration value="trillions"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_BuiltInUnit"> + <xsd:attribute name="val" type="ST_BuiltInUnit" default="thousands"/> + </xsd:complexType> + <xsd:simpleType name="ST_PictureFormat"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="stretch"/> + <xsd:enumeration value="stack"/> + <xsd:enumeration value="stackScale"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PictureFormat"> + <xsd:attribute name="val" type="ST_PictureFormat" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_PictureStackUnit"> + <xsd:restriction base="xsd:double"> + <xsd:minExclusive value="0"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PictureStackUnit"> + <xsd:attribute name="val" type="ST_PictureStackUnit" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_PictureOptions"> + <xsd:sequence> + <xsd:element name="applyToFront" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="applyToSides" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="applyToEnd" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pictureFormat" type="CT_PictureFormat" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pictureStackUnit" type="CT_PictureStackUnit" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DispUnitsLbl"> + <xsd:sequence> + <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tx" type="CT_Tx" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DispUnits"> + <xsd:sequence> + <xsd:choice> + <xsd:element name="custUnit" type="CT_Double" minOccurs="1" maxOccurs="1"/> + <xsd:element name="builtInUnit" type="CT_BuiltInUnit" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + <xsd:element name="dispUnitsLbl" type="CT_DispUnitsLbl" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_Orientation"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="maxMin"/> + <xsd:enumeration value="minMax"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Orientation"> + <xsd:attribute name="val" type="ST_Orientation" default="minMax"/> + </xsd:complexType> + <xsd:simpleType name="ST_LogBase"> + <xsd:restriction base="xsd:double"> + <xsd:minInclusive value="2"/> + <xsd:maxInclusive value="1000"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_LogBase"> + <xsd:attribute name="val" type="ST_LogBase" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Scaling"> + <xsd:sequence> + <xsd:element name="logBase" type="CT_LogBase" minOccurs="0" maxOccurs="1"/> + <xsd:element name="orientation" type="CT_Orientation" minOccurs="0" maxOccurs="1"/> + <xsd:element name="max" type="CT_Double" minOccurs="0" maxOccurs="1"/> + <xsd:element name="min" type="CT_Double" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_LblOffset"> + <xsd:union memberTypes="ST_LblOffsetPercent ST_LblOffsetUShort"/> + </xsd:simpleType> + <xsd:simpleType name="ST_LblOffsetPercent"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="0*(([0-9])|([1-9][0-9])|([1-9][0-9][0-9])|1000)%"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_LblOffsetUShort"> + <xsd:restriction base="xsd:unsignedShort"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="1000"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_LblOffset"> + <xsd:attribute name="val" type="ST_LblOffset" default="100%"/> + </xsd:complexType> + <xsd:group name="EG_AxShared"> + <xsd:sequence> + <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> + <xsd:element name="scaling" type="CT_Scaling" minOccurs="1" maxOccurs="1"/> + <xsd:element name="delete" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="axPos" type="CT_AxPos" minOccurs="1" maxOccurs="1"/> + <xsd:element name="majorGridlines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> + <xsd:element name="minorGridlines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> + <xsd:element name="title" type="CT_Title" minOccurs="0" maxOccurs="1"/> + <xsd:element name="numFmt" type="CT_NumFmt" minOccurs="0" maxOccurs="1"/> + <xsd:element name="majorTickMark" type="CT_TickMark" minOccurs="0" maxOccurs="1"/> + <xsd:element name="minorTickMark" type="CT_TickMark" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tickLblPos" type="CT_TickLblPos" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> + <xsd:element name="crossAx" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> + <xsd:choice minOccurs="0" maxOccurs="1"> + <xsd:element name="crosses" type="CT_Crosses" minOccurs="1" maxOccurs="1"/> + <xsd:element name="crossesAt" type="CT_Double" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_CatAx"> + <xsd:sequence> + <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="auto" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lblAlgn" type="CT_LblAlgn" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lblOffset" type="CT_LblOffset" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tickLblSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tickMarkSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> + <xsd:element name="noMultiLvlLbl" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DateAx"> + <xsd:sequence> + <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="auto" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lblOffset" type="CT_LblOffset" minOccurs="0" maxOccurs="1"/> + <xsd:element name="baseTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> + <xsd:element name="majorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> + <xsd:element name="majorTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> + <xsd:element name="minorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> + <xsd:element name="minorTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SerAx"> + <xsd:sequence> + <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="tickLblSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tickMarkSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ValAx"> + <xsd:sequence> + <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> + <xsd:element name="crossBetween" type="CT_CrossBetween" minOccurs="0" maxOccurs="1"/> + <xsd:element name="majorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> + <xsd:element name="minorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dispUnits" type="CT_DispUnits" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PlotArea"> + <xsd:sequence> + <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/> + <xsd:choice minOccurs="1" maxOccurs="unbounded"> + <xsd:element name="areaChart" type="CT_AreaChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="area3DChart" type="CT_Area3DChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lineChart" type="CT_LineChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="line3DChart" type="CT_Line3DChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="stockChart" type="CT_StockChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="radarChart" type="CT_RadarChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="scatterChart" type="CT_ScatterChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="pieChart" type="CT_PieChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="pie3DChart" type="CT_Pie3DChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="doughnutChart" type="CT_DoughnutChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="barChart" type="CT_BarChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="bar3DChart" type="CT_Bar3DChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="ofPieChart" type="CT_OfPieChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="surfaceChart" type="CT_SurfaceChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="surface3DChart" type="CT_Surface3DChart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="bubbleChart" type="CT_BubbleChart" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="valAx" type="CT_ValAx" minOccurs="1" maxOccurs="1"/> + <xsd:element name="catAx" type="CT_CatAx" minOccurs="1" maxOccurs="1"/> + <xsd:element name="dateAx" type="CT_DateAx" minOccurs="1" maxOccurs="1"/> + <xsd:element name="serAx" type="CT_SerAx" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + <xsd:element name="dTable" type="CT_DTable" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PivotFmt"> + <xsd:sequence> + <xsd:element name="idx" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> + <xsd:element name="marker" type="CT_Marker" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dLbl" type="CT_DLbl" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PivotFmts"> + <xsd:sequence> + <xsd:element name="pivotFmt" type="CT_PivotFmt" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_LegendPos"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="b"/> + <xsd:enumeration value="tr"/> + <xsd:enumeration value="l"/> + <xsd:enumeration value="r"/> + <xsd:enumeration value="t"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_LegendPos"> + <xsd:attribute name="val" type="ST_LegendPos" default="r"/> + </xsd:complexType> + <xsd:group name="EG_LegendEntryData"> + <xsd:sequence> + <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_LegendEntry"> + <xsd:sequence> + <xsd:element name="idx" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> + <xsd:choice> + <xsd:element name="delete" type="CT_Boolean" minOccurs="1" maxOccurs="1"/> + <xsd:group ref="EG_LegendEntryData" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Legend"> + <xsd:sequence> + <xsd:element name="legendPos" type="CT_LegendPos" minOccurs="0" maxOccurs="1"/> + <xsd:element name="legendEntry" type="CT_LegendEntry" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/> + <xsd:element name="overlay" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_DispBlanksAs"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="span"/> + <xsd:enumeration value="gap"/> + <xsd:enumeration value="zero"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_DispBlanksAs"> + <xsd:attribute name="val" type="ST_DispBlanksAs" default="zero"/> + </xsd:complexType> + <xsd:complexType name="CT_Chart"> + <xsd:sequence> + <xsd:element name="title" type="CT_Title" minOccurs="0" maxOccurs="1"/> + <xsd:element name="autoTitleDeleted" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pivotFmts" type="CT_PivotFmts" minOccurs="0" maxOccurs="1"/> + <xsd:element name="view3D" type="CT_View3D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="floor" type="CT_Surface" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sideWall" type="CT_Surface" minOccurs="0" maxOccurs="1"/> + <xsd:element name="backWall" type="CT_Surface" minOccurs="0" maxOccurs="1"/> + <xsd:element name="plotArea" type="CT_PlotArea" minOccurs="1" maxOccurs="1"/> + <xsd:element name="legend" type="CT_Legend" minOccurs="0" maxOccurs="1"/> + <xsd:element name="plotVisOnly" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dispBlanksAs" type="CT_DispBlanksAs" minOccurs="0" maxOccurs="1"/> + <xsd:element name="showDLblsOverMax" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_Style"> + <xsd:restriction base="xsd:unsignedByte"> + <xsd:minInclusive value="1"/> + <xsd:maxInclusive value="48"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Style"> + <xsd:attribute name="val" type="ST_Style" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_PivotSource"> + <xsd:sequence> + <xsd:element name="name" type="s:ST_Xstring" minOccurs="1" maxOccurs="1"/> + <xsd:element name="fmtId" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Protection"> + <xsd:sequence> + <xsd:element name="chartObject" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="data" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="formatting" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="selection" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="userInterface" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_HeaderFooter"> + <xsd:sequence> + <xsd:element name="oddHeader" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + <xsd:element name="oddFooter" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + <xsd:element name="evenHeader" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + <xsd:element name="evenFooter" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + <xsd:element name="firstHeader" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + <xsd:element name="firstFooter" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="alignWithMargins" type="xsd:boolean" default="true"/> + <xsd:attribute name="differentOddEven" type="xsd:boolean" default="false"/> + <xsd:attribute name="differentFirst" type="xsd:boolean" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_PageMargins"> + <xsd:attribute name="l" type="xsd:double" use="required"/> + <xsd:attribute name="r" type="xsd:double" use="required"/> + <xsd:attribute name="t" type="xsd:double" use="required"/> + <xsd:attribute name="b" type="xsd:double" use="required"/> + <xsd:attribute name="header" type="xsd:double" use="required"/> + <xsd:attribute name="footer" type="xsd:double" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_PageSetupOrientation"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="default"/> + <xsd:enumeration value="portrait"/> + <xsd:enumeration value="landscape"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_ExternalData"> + <xsd:sequence> + <xsd:element name="autoUpdate" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_PageSetup"> + <xsd:attribute name="paperSize" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute name="paperHeight" type="s:ST_PositiveUniversalMeasure" use="optional"/> + <xsd:attribute name="paperWidth" type="s:ST_PositiveUniversalMeasure" use="optional"/> + <xsd:attribute name="firstPageNumber" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute name="orientation" type="ST_PageSetupOrientation" use="optional" + default="default"/> + <xsd:attribute name="blackAndWhite" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="draft" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="useFirstPageNumber" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="horizontalDpi" type="xsd:int" use="optional" default="600"/> + <xsd:attribute name="verticalDpi" type="xsd:int" use="optional" default="600"/> + <xsd:attribute name="copies" type="xsd:unsignedInt" use="optional" default="1"/> + </xsd:complexType> + <xsd:complexType name="CT_PrintSettings"> + <xsd:sequence> + <xsd:element name="headerFooter" type="CT_HeaderFooter" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pageMargins" type="CT_PageMargins" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pageSetup" type="CT_PageSetup" minOccurs="0" maxOccurs="1"/> + <xsd:element name="legacyDrawingHF" type="CT_RelId" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ChartSpace"> + <xsd:sequence> + <xsd:element name="date1904" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lang" type="CT_TextLanguageID" minOccurs="0" maxOccurs="1"/> + <xsd:element name="roundedCorners" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> + <xsd:element name="style" type="CT_Style" minOccurs="0" maxOccurs="1"/> + <xsd:element name="clrMapOvr" type="a:CT_ColorMapping" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pivotSource" type="CT_PivotSource" minOccurs="0" maxOccurs="1"/> + <xsd:element name="protection" type="CT_Protection" minOccurs="0" maxOccurs="1"/> + <xsd:element name="chart" type="CT_Chart" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> + <xsd:element name="externalData" type="CT_ExternalData" minOccurs="0" maxOccurs="1"/> + <xsd:element name="printSettings" type="CT_PrintSettings" minOccurs="0" maxOccurs="1"/> + <xsd:element name="userShapes" type="CT_RelId" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="chartSpace" type="CT_ChartSpace"/> + <xsd:element name="userShapes" type="cdr:CT_Drawing"/> + <xsd:element name="chart" type="CT_RelId"/> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd new file mode 100644 index 0000000..afa4f46 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd @@ -0,0 +1,146 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" + xmlns="http://schemas.openxmlformats.org/drawingml/2006/chartDrawing" + targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/chartDrawing" + elementFormDefault="qualified"> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main" + schemaLocation="dml-main.xsd"/> + <xsd:complexType name="CT_ShapeNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvSpPr" type="a:CT_NonVisualDrawingShapeProps" minOccurs="1" maxOccurs="1" + /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Shape"> + <xsd:sequence> + <xsd:element name="nvSpPr" type="CT_ShapeNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txBody" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="macro" type="xsd:string" use="optional"/> + <xsd:attribute name="textlink" type="xsd:string" use="optional"/> + <xsd:attribute name="fLocksText" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_ConnectorNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvCxnSpPr" type="a:CT_NonVisualConnectorProperties" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Connector"> + <xsd:sequence> + <xsd:element name="nvCxnSpPr" type="CT_ConnectorNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="macro" type="xsd:string" use="optional"/> + <xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_PictureNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvPicPr" type="a:CT_NonVisualPictureProperties" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Picture"> + <xsd:sequence> + <xsd:element name="nvPicPr" type="CT_PictureNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="blipFill" type="a:CT_BlipFillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="macro" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_GraphicFrameNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties" + minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GraphicFrame"> + <xsd:sequence> + <xsd:element name="nvGraphicFramePr" type="CT_GraphicFrameNonVisual" minOccurs="1" + maxOccurs="1"/> + <xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="1" maxOccurs="1"/> + <xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="macro" type="xsd:string" use="optional"/> + <xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_GroupShapeNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvGrpSpPr" type="a:CT_NonVisualGroupDrawingShapeProps" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GroupShape"> + <xsd:sequence> + <xsd:element name="nvGrpSpPr" type="CT_GroupShapeNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="grpSpPr" type="a:CT_GroupShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="sp" type="CT_Shape"/> + <xsd:element name="grpSp" type="CT_GroupShape"/> + <xsd:element name="graphicFrame" type="CT_GraphicFrame"/> + <xsd:element name="cxnSp" type="CT_Connector"/> + <xsd:element name="pic" type="CT_Picture"/> + </xsd:choice> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_ObjectChoices"> + <xsd:sequence> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="sp" type="CT_Shape"/> + <xsd:element name="grpSp" type="CT_GroupShape"/> + <xsd:element name="graphicFrame" type="CT_GraphicFrame"/> + <xsd:element name="cxnSp" type="CT_Connector"/> + <xsd:element name="pic" type="CT_Picture"/> + </xsd:choice> + </xsd:sequence> + </xsd:group> + <xsd:simpleType name="ST_MarkerCoordinate"> + <xsd:restriction base="xsd:double"> + <xsd:minInclusive value="0.0"/> + <xsd:maxInclusive value="1.0"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Marker"> + <xsd:sequence> + <xsd:element name="x" type="ST_MarkerCoordinate" minOccurs="1" maxOccurs="1"/> + <xsd:element name="y" type="ST_MarkerCoordinate" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_RelSizeAnchor"> + <xsd:sequence> + <xsd:element name="from" type="CT_Marker"/> + <xsd:element name="to" type="CT_Marker"/> + <xsd:group ref="EG_ObjectChoices"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_AbsSizeAnchor"> + <xsd:sequence> + <xsd:element name="from" type="CT_Marker"/> + <xsd:element name="ext" type="a:CT_PositiveSize2D"/> + <xsd:group ref="EG_ObjectChoices"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_Anchor"> + <xsd:choice> + <xsd:element name="relSizeAnchor" type="CT_RelSizeAnchor"/> + <xsd:element name="absSizeAnchor" type="CT_AbsSizeAnchor"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_Drawing"> + <xsd:sequence> + <xsd:group ref="EG_Anchor" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd new file mode 100644 index 0000000..64e66b8 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd @@ -0,0 +1,1085 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/drawingml/2006/diagram" + xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" + xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/diagram" + elementFormDefault="qualified" attributeFormDefault="unqualified"> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + schemaLocation="shared-relationshipReference.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main" + schemaLocation="dml-main.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + schemaLocation="shared-commonSimpleTypes.xsd"/> + <xsd:complexType name="CT_CTName"> + <xsd:attribute name="lang" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="val" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CTDescription"> + <xsd:attribute name="lang" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="val" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CTCategory"> + <xsd:attribute name="type" type="xsd:anyURI" use="required"/> + <xsd:attribute name="pri" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CTCategories"> + <xsd:sequence minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="cat" type="CT_CTCategory" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_ClrAppMethod"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="span"/> + <xsd:enumeration value="cycle"/> + <xsd:enumeration value="repeat"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_HueDir"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="cw"/> + <xsd:enumeration value="ccw"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Colors"> + <xsd:sequence> + <xsd:group ref="a:EG_ColorChoice" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="meth" type="ST_ClrAppMethod" use="optional" default="span"/> + <xsd:attribute name="hueDir" type="ST_HueDir" use="optional" default="cw"/> + </xsd:complexType> + <xsd:complexType name="CT_CTStyleLabel"> + <xsd:sequence> + <xsd:element name="fillClrLst" type="CT_Colors" minOccurs="0" maxOccurs="1"/> + <xsd:element name="linClrLst" type="CT_Colors" minOccurs="0" maxOccurs="1"/> + <xsd:element name="effectClrLst" type="CT_Colors" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txLinClrLst" type="CT_Colors" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txFillClrLst" type="CT_Colors" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txEffectClrLst" type="CT_Colors" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_ColorTransform"> + <xsd:sequence> + <xsd:element name="title" type="CT_CTName" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="desc" type="CT_CTDescription" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="catLst" type="CT_CTCategories" minOccurs="0"/> + <xsd:element name="styleLbl" type="CT_CTStyleLabel" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="uniqueId" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="minVer" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:element name="colorsDef" type="CT_ColorTransform"/> + <xsd:complexType name="CT_ColorTransformHeader"> + <xsd:sequence> + <xsd:element name="title" type="CT_CTName" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="desc" type="CT_CTDescription" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="catLst" type="CT_CTCategories" minOccurs="0"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="uniqueId" type="xsd:string" use="required"/> + <xsd:attribute name="minVer" type="xsd:string" use="optional"/> + <xsd:attribute name="resId" type="xsd:int" use="optional" default="0"/> + </xsd:complexType> + <xsd:element name="colorsDefHdr" type="CT_ColorTransformHeader"/> + <xsd:complexType name="CT_ColorTransformHeaderLst"> + <xsd:sequence> + <xsd:element name="colorsDefHdr" type="CT_ColorTransformHeader" minOccurs="0" + maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="colorsDefHdrLst" type="CT_ColorTransformHeaderLst"/> + <xsd:simpleType name="ST_PtType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="node"/> + <xsd:enumeration value="asst"/> + <xsd:enumeration value="doc"/> + <xsd:enumeration value="pres"/> + <xsd:enumeration value="parTrans"/> + <xsd:enumeration value="sibTrans"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Pt"> + <xsd:sequence> + <xsd:element name="prSet" type="CT_ElemPropSet" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="t" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="modelId" type="ST_ModelId" use="required"/> + <xsd:attribute name="type" type="ST_PtType" use="optional" default="node"/> + <xsd:attribute name="cxnId" type="ST_ModelId" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_PtList"> + <xsd:sequence> + <xsd:element name="pt" type="CT_Pt" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_CxnType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="parOf"/> + <xsd:enumeration value="presOf"/> + <xsd:enumeration value="presParOf"/> + <xsd:enumeration value="unknownRelationship"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Cxn"> + <xsd:sequence> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="modelId" type="ST_ModelId" use="required"/> + <xsd:attribute name="type" type="ST_CxnType" use="optional" default="parOf"/> + <xsd:attribute name="srcId" type="ST_ModelId" use="required"/> + <xsd:attribute name="destId" type="ST_ModelId" use="required"/> + <xsd:attribute name="srcOrd" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="destOrd" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="parTransId" type="ST_ModelId" use="optional" default="0"/> + <xsd:attribute name="sibTransId" type="ST_ModelId" use="optional" default="0"/> + <xsd:attribute name="presId" type="xsd:string" use="optional" default=""/> + </xsd:complexType> + <xsd:complexType name="CT_CxnList"> + <xsd:sequence> + <xsd:element name="cxn" type="CT_Cxn" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DataModel"> + <xsd:sequence> + <xsd:element name="ptLst" type="CT_PtList"/> + <xsd:element name="cxnLst" type="CT_CxnList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bg" type="a:CT_BackgroundFormatting" minOccurs="0"/> + <xsd:element name="whole" type="a:CT_WholeE2oFormatting" minOccurs="0"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="dataModel" type="CT_DataModel"/> + <xsd:attributeGroup name="AG_IteratorAttributes"> + <xsd:attribute name="axis" type="ST_AxisTypes" use="optional" default="none"/> + <xsd:attribute name="ptType" type="ST_ElementTypes" use="optional" default="all"/> + <xsd:attribute name="hideLastTrans" type="ST_Booleans" use="optional" default="true"/> + <xsd:attribute name="st" type="ST_Ints" use="optional" default="1"/> + <xsd:attribute name="cnt" type="ST_UnsignedInts" use="optional" default="0"/> + <xsd:attribute name="step" type="ST_Ints" use="optional" default="1"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_ConstraintAttributes"> + <xsd:attribute name="type" type="ST_ConstraintType" use="required"/> + <xsd:attribute name="for" type="ST_ConstraintRelationship" use="optional" default="self"/> + <xsd:attribute name="forName" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="ptType" type="ST_ElementType" use="optional" default="all"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_ConstraintRefAttributes"> + <xsd:attribute name="refType" type="ST_ConstraintType" use="optional" default="none"/> + <xsd:attribute name="refFor" type="ST_ConstraintRelationship" use="optional" default="self"/> + <xsd:attribute name="refForName" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="refPtType" type="ST_ElementType" use="optional" default="all"/> + </xsd:attributeGroup> + <xsd:complexType name="CT_Constraint"> + <xsd:sequence> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_ConstraintAttributes"/> + <xsd:attributeGroup ref="AG_ConstraintRefAttributes"/> + <xsd:attribute name="op" type="ST_BoolOperator" use="optional" default="none"/> + <xsd:attribute name="val" type="xsd:double" use="optional" default="0"/> + <xsd:attribute name="fact" type="xsd:double" use="optional" default="1"/> + </xsd:complexType> + <xsd:complexType name="CT_Constraints"> + <xsd:sequence> + <xsd:element name="constr" type="CT_Constraint" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_NumericRule"> + <xsd:sequence> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_ConstraintAttributes"/> + <xsd:attribute name="val" type="xsd:double" use="optional" default="NaN"/> + <xsd:attribute name="fact" type="xsd:double" use="optional" default="NaN"/> + <xsd:attribute name="max" type="xsd:double" use="optional" default="NaN"/> + </xsd:complexType> + <xsd:complexType name="CT_Rules"> + <xsd:sequence> + <xsd:element name="rule" type="CT_NumericRule" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PresentationOf"> + <xsd:sequence> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_IteratorAttributes"/> + </xsd:complexType> + <xsd:simpleType name="ST_LayoutShapeType" final="restriction"> + <xsd:union memberTypes="a:ST_ShapeType ST_OutputShapeType"/> + </xsd:simpleType> + <xsd:simpleType name="ST_Index1"> + <xsd:restriction base="xsd:unsignedInt"> + <xsd:minInclusive value="1"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Adj"> + <xsd:attribute name="idx" type="ST_Index1" use="required"/> + <xsd:attribute name="val" type="xsd:double" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_AdjLst"> + <xsd:sequence> + <xsd:element name="adj" type="CT_Adj" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Shape"> + <xsd:sequence> + <xsd:element name="adjLst" type="CT_AdjLst" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="rot" type="xsd:double" use="optional" default="0"/> + <xsd:attribute name="type" type="ST_LayoutShapeType" use="optional" default="none"/> + <xsd:attribute ref="r:blip" use="optional"/> + <xsd:attribute name="zOrderOff" type="xsd:int" use="optional" default="0"/> + <xsd:attribute name="hideGeom" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="lkTxEntry" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="blipPhldr" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_Parameter"> + <xsd:attribute name="type" type="ST_ParameterId" use="required"/> + <xsd:attribute name="val" type="ST_ParameterVal" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Algorithm"> + <xsd:sequence> + <xsd:element name="param" type="CT_Parameter" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="type" type="ST_AlgorithmType" use="required"/> + <xsd:attribute name="rev" type="xsd:unsignedInt" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_LayoutNode"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="alg" type="CT_Algorithm" minOccurs="0" maxOccurs="1"/> + <xsd:element name="shape" type="CT_Shape" minOccurs="0" maxOccurs="1"/> + <xsd:element name="presOf" type="CT_PresentationOf" minOccurs="0" maxOccurs="1"/> + <xsd:element name="constrLst" type="CT_Constraints" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ruleLst" type="CT_Rules" minOccurs="0" maxOccurs="1"/> + <xsd:element name="varLst" type="CT_LayoutVariablePropertySet" minOccurs="0" maxOccurs="1"/> + <xsd:element name="forEach" type="CT_ForEach"/> + <xsd:element name="layoutNode" type="CT_LayoutNode"/> + <xsd:element name="choose" type="CT_Choose"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="styleLbl" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="chOrder" type="ST_ChildOrderType" use="optional" default="b"/> + <xsd:attribute name="moveWith" type="xsd:string" use="optional" default=""/> + </xsd:complexType> + <xsd:complexType name="CT_ForEach"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="alg" type="CT_Algorithm" minOccurs="0" maxOccurs="1"/> + <xsd:element name="shape" type="CT_Shape" minOccurs="0" maxOccurs="1"/> + <xsd:element name="presOf" type="CT_PresentationOf" minOccurs="0" maxOccurs="1"/> + <xsd:element name="constrLst" type="CT_Constraints" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ruleLst" type="CT_Rules" minOccurs="0" maxOccurs="1"/> + <xsd:element name="forEach" type="CT_ForEach"/> + <xsd:element name="layoutNode" type="CT_LayoutNode"/> + <xsd:element name="choose" type="CT_Choose"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="ref" type="xsd:string" use="optional" default=""/> + <xsd:attributeGroup ref="AG_IteratorAttributes"/> + </xsd:complexType> + <xsd:complexType name="CT_When"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="alg" type="CT_Algorithm" minOccurs="0" maxOccurs="1"/> + <xsd:element name="shape" type="CT_Shape" minOccurs="0" maxOccurs="1"/> + <xsd:element name="presOf" type="CT_PresentationOf" minOccurs="0" maxOccurs="1"/> + <xsd:element name="constrLst" type="CT_Constraints" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ruleLst" type="CT_Rules" minOccurs="0" maxOccurs="1"/> + <xsd:element name="forEach" type="CT_ForEach"/> + <xsd:element name="layoutNode" type="CT_LayoutNode"/> + <xsd:element name="choose" type="CT_Choose"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:string" use="optional" default=""/> + <xsd:attributeGroup ref="AG_IteratorAttributes"/> + <xsd:attribute name="func" type="ST_FunctionType" use="required"/> + <xsd:attribute name="arg" type="ST_FunctionArgument" use="optional" default="none"/> + <xsd:attribute name="op" type="ST_FunctionOperator" use="required"/> + <xsd:attribute name="val" type="ST_FunctionValue" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Otherwise"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="alg" type="CT_Algorithm" minOccurs="0" maxOccurs="1"/> + <xsd:element name="shape" type="CT_Shape" minOccurs="0" maxOccurs="1"/> + <xsd:element name="presOf" type="CT_PresentationOf" minOccurs="0" maxOccurs="1"/> + <xsd:element name="constrLst" type="CT_Constraints" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ruleLst" type="CT_Rules" minOccurs="0" maxOccurs="1"/> + <xsd:element name="forEach" type="CT_ForEach"/> + <xsd:element name="layoutNode" type="CT_LayoutNode"/> + <xsd:element name="choose" type="CT_Choose"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:choice> + <xsd:attribute name="name" type="xsd:string" use="optional" default=""/> + </xsd:complexType> + <xsd:complexType name="CT_Choose"> + <xsd:sequence> + <xsd:element name="if" type="CT_When" maxOccurs="unbounded"/> + <xsd:element name="else" type="CT_Otherwise" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="optional" default=""/> + </xsd:complexType> + <xsd:complexType name="CT_SampleData"> + <xsd:sequence> + <xsd:element name="dataModel" type="CT_DataModel" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="useDef" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_Category"> + <xsd:attribute name="type" type="xsd:anyURI" use="required"/> + <xsd:attribute name="pri" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Categories"> + <xsd:sequence> + <xsd:element name="cat" type="CT_Category" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Name"> + <xsd:attribute name="lang" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="val" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Description"> + <xsd:attribute name="lang" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="val" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_DiagramDefinition"> + <xsd:sequence> + <xsd:element name="title" type="CT_Name" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="desc" type="CT_Description" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="catLst" type="CT_Categories" minOccurs="0"/> + <xsd:element name="sampData" type="CT_SampleData" minOccurs="0"/> + <xsd:element name="styleData" type="CT_SampleData" minOccurs="0"/> + <xsd:element name="clrData" type="CT_SampleData" minOccurs="0"/> + <xsd:element name="layoutNode" type="CT_LayoutNode"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="uniqueId" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="minVer" type="xsd:string" use="optional"/> + <xsd:attribute name="defStyle" type="xsd:string" use="optional" default=""/> + </xsd:complexType> + <xsd:element name="layoutDef" type="CT_DiagramDefinition"/> + <xsd:complexType name="CT_DiagramDefinitionHeader"> + <xsd:sequence> + <xsd:element name="title" type="CT_Name" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="desc" type="CT_Description" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="catLst" type="CT_Categories" minOccurs="0"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="uniqueId" type="xsd:string" use="required"/> + <xsd:attribute name="minVer" type="xsd:string" use="optional"/> + <xsd:attribute name="defStyle" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="resId" type="xsd:int" use="optional" default="0"/> + </xsd:complexType> + <xsd:element name="layoutDefHdr" type="CT_DiagramDefinitionHeader"/> + <xsd:complexType name="CT_DiagramDefinitionHeaderLst"> + <xsd:sequence> + <xsd:element name="layoutDefHdr" type="CT_DiagramDefinitionHeader" minOccurs="0" + maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="layoutDefHdrLst" type="CT_DiagramDefinitionHeaderLst"/> + <xsd:complexType name="CT_RelIds"> + <xsd:attribute ref="r:dm" use="required"/> + <xsd:attribute ref="r:lo" use="required"/> + <xsd:attribute ref="r:qs" use="required"/> + <xsd:attribute ref="r:cs" use="required"/> + </xsd:complexType> + <xsd:element name="relIds" type="CT_RelIds"/> + <xsd:simpleType name="ST_ParameterVal"> + <xsd:union + memberTypes="ST_DiagramHorizontalAlignment ST_VerticalAlignment ST_ChildDirection ST_ChildAlignment ST_SecondaryChildAlignment ST_LinearDirection ST_SecondaryLinearDirection ST_StartingElement ST_BendPoint ST_ConnectorRouting ST_ArrowheadStyle ST_ConnectorDimension ST_RotationPath ST_CenterShapeMapping ST_NodeHorizontalAlignment ST_NodeVerticalAlignment ST_FallbackDimension ST_TextDirection ST_PyramidAccentPosition ST_PyramidAccentTextMargin ST_TextBlockDirection ST_TextAnchorHorizontal ST_TextAnchorVertical ST_DiagramTextAlignment ST_AutoTextRotation ST_GrowDirection ST_FlowDirection ST_ContinueDirection ST_Breakpoint ST_Offset ST_HierarchyAlignment xsd:int xsd:double xsd:boolean xsd:string ST_ConnectorPoint" + /> + </xsd:simpleType> + <xsd:simpleType name="ST_ModelId"> + <xsd:union memberTypes="xsd:int s:ST_Guid"/> + </xsd:simpleType> + <xsd:simpleType name="ST_PrSetCustVal"> + <xsd:union memberTypes="s:ST_Percentage xsd:int"/> + </xsd:simpleType> + <xsd:complexType name="CT_ElemPropSet"> + <xsd:sequence> + <xsd:element name="presLayoutVars" type="CT_LayoutVariablePropertySet" minOccurs="0" + maxOccurs="1"/> + <xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="presAssocID" type="ST_ModelId" use="optional"/> + <xsd:attribute name="presName" type="xsd:string" use="optional"/> + <xsd:attribute name="presStyleLbl" type="xsd:string" use="optional"/> + <xsd:attribute name="presStyleIdx" type="xsd:int" use="optional"/> + <xsd:attribute name="presStyleCnt" type="xsd:int" use="optional"/> + <xsd:attribute name="loTypeId" type="xsd:string" use="optional"/> + <xsd:attribute name="loCatId" type="xsd:string" use="optional"/> + <xsd:attribute name="qsTypeId" type="xsd:string" use="optional"/> + <xsd:attribute name="qsCatId" type="xsd:string" use="optional"/> + <xsd:attribute name="csTypeId" type="xsd:string" use="optional"/> + <xsd:attribute name="csCatId" type="xsd:string" use="optional"/> + <xsd:attribute name="coherent3DOff" type="xsd:boolean" use="optional"/> + <xsd:attribute name="phldrT" type="xsd:string" use="optional"/> + <xsd:attribute name="phldr" type="xsd:boolean" use="optional"/> + <xsd:attribute name="custAng" type="xsd:int" use="optional"/> + <xsd:attribute name="custFlipVert" type="xsd:boolean" use="optional"/> + <xsd:attribute name="custFlipHor" type="xsd:boolean" use="optional"/> + <xsd:attribute name="custSzX" type="xsd:int" use="optional"/> + <xsd:attribute name="custSzY" type="xsd:int" use="optional"/> + <xsd:attribute name="custScaleX" type="ST_PrSetCustVal" use="optional"/> + <xsd:attribute name="custScaleY" type="ST_PrSetCustVal" use="optional"/> + <xsd:attribute name="custT" type="xsd:boolean" use="optional"/> + <xsd:attribute name="custLinFactX" type="ST_PrSetCustVal" use="optional"/> + <xsd:attribute name="custLinFactY" type="ST_PrSetCustVal" use="optional"/> + <xsd:attribute name="custLinFactNeighborX" type="ST_PrSetCustVal" use="optional"/> + <xsd:attribute name="custLinFactNeighborY" type="ST_PrSetCustVal" use="optional"/> + <xsd:attribute name="custRadScaleRad" type="ST_PrSetCustVal" use="optional"/> + <xsd:attribute name="custRadScaleInc" type="ST_PrSetCustVal" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_Direction" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="norm"/> + <xsd:enumeration value="rev"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_HierBranchStyle" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="l"/> + <xsd:enumeration value="r"/> + <xsd:enumeration value="hang"/> + <xsd:enumeration value="std"/> + <xsd:enumeration value="init"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_AnimOneStr" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="one"/> + <xsd:enumeration value="branch"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_AnimLvlStr" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="lvl"/> + <xsd:enumeration value="ctr"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_OrgChart"> + <xsd:attribute name="val" type="xsd:boolean" default="false" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_NodeCount"> + <xsd:restriction base="xsd:int"> + <xsd:minInclusive value="-1"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_ChildMax"> + <xsd:attribute name="val" type="ST_NodeCount" default="-1" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_ChildPref"> + <xsd:attribute name="val" type="ST_NodeCount" default="-1" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_BulletEnabled"> + <xsd:attribute name="val" type="xsd:boolean" default="false" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Direction"> + <xsd:attribute name="val" type="ST_Direction" default="norm" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_HierBranchStyle"> + <xsd:attribute name="val" type="ST_HierBranchStyle" default="std" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_AnimOne"> + <xsd:attribute name="val" type="ST_AnimOneStr" default="one" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_AnimLvl"> + <xsd:attribute name="val" type="ST_AnimLvlStr" default="none" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_ResizeHandlesStr" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="exact"/> + <xsd:enumeration value="rel"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_ResizeHandles"> + <xsd:attribute name="val" type="ST_ResizeHandlesStr" default="rel" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_LayoutVariablePropertySet"> + <xsd:sequence> + <xsd:element name="orgChart" type="CT_OrgChart" minOccurs="0" maxOccurs="1"/> + <xsd:element name="chMax" type="CT_ChildMax" minOccurs="0" maxOccurs="1"/> + <xsd:element name="chPref" type="CT_ChildPref" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bulletEnabled" type="CT_BulletEnabled" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dir" type="CT_Direction" minOccurs="0" maxOccurs="1"/> + <xsd:element name="hierBranch" type="CT_HierBranchStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="animOne" type="CT_AnimOne" minOccurs="0" maxOccurs="1"/> + <xsd:element name="animLvl" type="CT_AnimLvl" minOccurs="0" maxOccurs="1"/> + <xsd:element name="resizeHandles" type="CT_ResizeHandles" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SDName"> + <xsd:attribute name="lang" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="val" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SDDescription"> + <xsd:attribute name="lang" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="val" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SDCategory"> + <xsd:attribute name="type" type="xsd:anyURI" use="required"/> + <xsd:attribute name="pri" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SDCategories"> + <xsd:sequence minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="cat" type="CT_SDCategory" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TextProps"> + <xsd:sequence> + <xsd:group ref="a:EG_Text3D" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_StyleLabel"> + <xsd:sequence> + <xsd:element name="scene3d" type="a:CT_Scene3D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sp3d" type="a:CT_Shape3D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txPr" type="CT_TextProps" minOccurs="0" maxOccurs="1"/> + <xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_StyleDefinition"> + <xsd:sequence> + <xsd:element name="title" type="CT_SDName" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="desc" type="CT_SDDescription" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="catLst" type="CT_SDCategories" minOccurs="0"/> + <xsd:element name="scene3d" type="a:CT_Scene3D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="styleLbl" type="CT_StyleLabel" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="uniqueId" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="minVer" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:element name="styleDef" type="CT_StyleDefinition"/> + <xsd:complexType name="CT_StyleDefinitionHeader"> + <xsd:sequence> + <xsd:element name="title" type="CT_SDName" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="desc" type="CT_SDDescription" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="catLst" type="CT_SDCategories" minOccurs="0"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="uniqueId" type="xsd:string" use="required"/> + <xsd:attribute name="minVer" type="xsd:string" use="optional"/> + <xsd:attribute name="resId" type="xsd:int" use="optional" default="0"/> + </xsd:complexType> + <xsd:element name="styleDefHdr" type="CT_StyleDefinitionHeader"/> + <xsd:complexType name="CT_StyleDefinitionHeaderLst"> + <xsd:sequence> + <xsd:element name="styleDefHdr" type="CT_StyleDefinitionHeader" minOccurs="0" + maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="styleDefHdrLst" type="CT_StyleDefinitionHeaderLst"/> + <xsd:simpleType name="ST_AlgorithmType" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="composite"/> + <xsd:enumeration value="conn"/> + <xsd:enumeration value="cycle"/> + <xsd:enumeration value="hierChild"/> + <xsd:enumeration value="hierRoot"/> + <xsd:enumeration value="pyra"/> + <xsd:enumeration value="lin"/> + <xsd:enumeration value="sp"/> + <xsd:enumeration value="tx"/> + <xsd:enumeration value="snake"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_AxisType" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="self"/> + <xsd:enumeration value="ch"/> + <xsd:enumeration value="des"/> + <xsd:enumeration value="desOrSelf"/> + <xsd:enumeration value="par"/> + <xsd:enumeration value="ancst"/> + <xsd:enumeration value="ancstOrSelf"/> + <xsd:enumeration value="followSib"/> + <xsd:enumeration value="precedSib"/> + <xsd:enumeration value="follow"/> + <xsd:enumeration value="preced"/> + <xsd:enumeration value="root"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_AxisTypes"> + <xsd:list itemType="ST_AxisType"/> + </xsd:simpleType> + <xsd:simpleType name="ST_BoolOperator" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="equ"/> + <xsd:enumeration value="gte"/> + <xsd:enumeration value="lte"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ChildOrderType" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="b"/> + <xsd:enumeration value="t"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ConstraintType" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="alignOff"/> + <xsd:enumeration value="begMarg"/> + <xsd:enumeration value="bendDist"/> + <xsd:enumeration value="begPad"/> + <xsd:enumeration value="b"/> + <xsd:enumeration value="bMarg"/> + <xsd:enumeration value="bOff"/> + <xsd:enumeration value="ctrX"/> + <xsd:enumeration value="ctrXOff"/> + <xsd:enumeration value="ctrY"/> + <xsd:enumeration value="ctrYOff"/> + <xsd:enumeration value="connDist"/> + <xsd:enumeration value="diam"/> + <xsd:enumeration value="endMarg"/> + <xsd:enumeration value="endPad"/> + <xsd:enumeration value="h"/> + <xsd:enumeration value="hArH"/> + <xsd:enumeration value="hOff"/> + <xsd:enumeration value="l"/> + <xsd:enumeration value="lMarg"/> + <xsd:enumeration value="lOff"/> + <xsd:enumeration value="r"/> + <xsd:enumeration value="rMarg"/> + <xsd:enumeration value="rOff"/> + <xsd:enumeration value="primFontSz"/> + <xsd:enumeration value="pyraAcctRatio"/> + <xsd:enumeration value="secFontSz"/> + <xsd:enumeration value="sibSp"/> + <xsd:enumeration value="secSibSp"/> + <xsd:enumeration value="sp"/> + <xsd:enumeration value="stemThick"/> + <xsd:enumeration value="t"/> + <xsd:enumeration value="tMarg"/> + <xsd:enumeration value="tOff"/> + <xsd:enumeration value="userA"/> + <xsd:enumeration value="userB"/> + <xsd:enumeration value="userC"/> + <xsd:enumeration value="userD"/> + <xsd:enumeration value="userE"/> + <xsd:enumeration value="userF"/> + <xsd:enumeration value="userG"/> + <xsd:enumeration value="userH"/> + <xsd:enumeration value="userI"/> + <xsd:enumeration value="userJ"/> + <xsd:enumeration value="userK"/> + <xsd:enumeration value="userL"/> + <xsd:enumeration value="userM"/> + <xsd:enumeration value="userN"/> + <xsd:enumeration value="userO"/> + <xsd:enumeration value="userP"/> + <xsd:enumeration value="userQ"/> + <xsd:enumeration value="userR"/> + <xsd:enumeration value="userS"/> + <xsd:enumeration value="userT"/> + <xsd:enumeration value="userU"/> + <xsd:enumeration value="userV"/> + <xsd:enumeration value="userW"/> + <xsd:enumeration value="userX"/> + <xsd:enumeration value="userY"/> + <xsd:enumeration value="userZ"/> + <xsd:enumeration value="w"/> + <xsd:enumeration value="wArH"/> + <xsd:enumeration value="wOff"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ConstraintRelationship" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="self"/> + <xsd:enumeration value="ch"/> + <xsd:enumeration value="des"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ElementType" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="all"/> + <xsd:enumeration value="doc"/> + <xsd:enumeration value="node"/> + <xsd:enumeration value="norm"/> + <xsd:enumeration value="nonNorm"/> + <xsd:enumeration value="asst"/> + <xsd:enumeration value="nonAsst"/> + <xsd:enumeration value="parTrans"/> + <xsd:enumeration value="pres"/> + <xsd:enumeration value="sibTrans"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ElementTypes"> + <xsd:list itemType="ST_ElementType"/> + </xsd:simpleType> + <xsd:simpleType name="ST_ParameterId" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="horzAlign"/> + <xsd:enumeration value="vertAlign"/> + <xsd:enumeration value="chDir"/> + <xsd:enumeration value="chAlign"/> + <xsd:enumeration value="secChAlign"/> + <xsd:enumeration value="linDir"/> + <xsd:enumeration value="secLinDir"/> + <xsd:enumeration value="stElem"/> + <xsd:enumeration value="bendPt"/> + <xsd:enumeration value="connRout"/> + <xsd:enumeration value="begSty"/> + <xsd:enumeration value="endSty"/> + <xsd:enumeration value="dim"/> + <xsd:enumeration value="rotPath"/> + <xsd:enumeration value="ctrShpMap"/> + <xsd:enumeration value="nodeHorzAlign"/> + <xsd:enumeration value="nodeVertAlign"/> + <xsd:enumeration value="fallback"/> + <xsd:enumeration value="txDir"/> + <xsd:enumeration value="pyraAcctPos"/> + <xsd:enumeration value="pyraAcctTxMar"/> + <xsd:enumeration value="txBlDir"/> + <xsd:enumeration value="txAnchorHorz"/> + <xsd:enumeration value="txAnchorVert"/> + <xsd:enumeration value="txAnchorHorzCh"/> + <xsd:enumeration value="txAnchorVertCh"/> + <xsd:enumeration value="parTxLTRAlign"/> + <xsd:enumeration value="parTxRTLAlign"/> + <xsd:enumeration value="shpTxLTRAlignCh"/> + <xsd:enumeration value="shpTxRTLAlignCh"/> + <xsd:enumeration value="autoTxRot"/> + <xsd:enumeration value="grDir"/> + <xsd:enumeration value="flowDir"/> + <xsd:enumeration value="contDir"/> + <xsd:enumeration value="bkpt"/> + <xsd:enumeration value="off"/> + <xsd:enumeration value="hierAlign"/> + <xsd:enumeration value="bkPtFixedVal"/> + <xsd:enumeration value="stBulletLvl"/> + <xsd:enumeration value="stAng"/> + <xsd:enumeration value="spanAng"/> + <xsd:enumeration value="ar"/> + <xsd:enumeration value="lnSpPar"/> + <xsd:enumeration value="lnSpAfParP"/> + <xsd:enumeration value="lnSpCh"/> + <xsd:enumeration value="lnSpAfChP"/> + <xsd:enumeration value="rtShortDist"/> + <xsd:enumeration value="alignTx"/> + <xsd:enumeration value="pyraLvlNode"/> + <xsd:enumeration value="pyraAcctBkgdNode"/> + <xsd:enumeration value="pyraAcctTxNode"/> + <xsd:enumeration value="srcNode"/> + <xsd:enumeration value="dstNode"/> + <xsd:enumeration value="begPts"/> + <xsd:enumeration value="endPts"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Ints"> + <xsd:list itemType="xsd:int"/> + </xsd:simpleType> + <xsd:simpleType name="ST_UnsignedInts"> + <xsd:list itemType="xsd:unsignedInt"/> + </xsd:simpleType> + <xsd:simpleType name="ST_Booleans"> + <xsd:list itemType="xsd:boolean"/> + </xsd:simpleType> + <xsd:simpleType name="ST_FunctionType" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="cnt"/> + <xsd:enumeration value="pos"/> + <xsd:enumeration value="revPos"/> + <xsd:enumeration value="posEven"/> + <xsd:enumeration value="posOdd"/> + <xsd:enumeration value="var"/> + <xsd:enumeration value="depth"/> + <xsd:enumeration value="maxDepth"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FunctionOperator" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="equ"/> + <xsd:enumeration value="neq"/> + <xsd:enumeration value="gt"/> + <xsd:enumeration value="lt"/> + <xsd:enumeration value="gte"/> + <xsd:enumeration value="lte"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_DiagramHorizontalAlignment" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="l"/> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="r"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_VerticalAlignment" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="t"/> + <xsd:enumeration value="mid"/> + <xsd:enumeration value="b"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ChildDirection" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="horz"/> + <xsd:enumeration value="vert"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ChildAlignment" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="t"/> + <xsd:enumeration value="b"/> + <xsd:enumeration value="l"/> + <xsd:enumeration value="r"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_SecondaryChildAlignment" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="t"/> + <xsd:enumeration value="b"/> + <xsd:enumeration value="l"/> + <xsd:enumeration value="r"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_LinearDirection" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="fromL"/> + <xsd:enumeration value="fromR"/> + <xsd:enumeration value="fromT"/> + <xsd:enumeration value="fromB"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_SecondaryLinearDirection" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="fromL"/> + <xsd:enumeration value="fromR"/> + <xsd:enumeration value="fromT"/> + <xsd:enumeration value="fromB"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_StartingElement" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="node"/> + <xsd:enumeration value="trans"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_RotationPath" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="alongPath"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_CenterShapeMapping" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="fNode"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_BendPoint" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="beg"/> + <xsd:enumeration value="def"/> + <xsd:enumeration value="end"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ConnectorRouting" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="stra"/> + <xsd:enumeration value="bend"/> + <xsd:enumeration value="curve"/> + <xsd:enumeration value="longCurve"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ArrowheadStyle" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="auto"/> + <xsd:enumeration value="arr"/> + <xsd:enumeration value="noArr"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ConnectorDimension" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="1D"/> + <xsd:enumeration value="2D"/> + <xsd:enumeration value="cust"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ConnectorPoint" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="auto"/> + <xsd:enumeration value="bCtr"/> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="midL"/> + <xsd:enumeration value="midR"/> + <xsd:enumeration value="tCtr"/> + <xsd:enumeration value="bL"/> + <xsd:enumeration value="bR"/> + <xsd:enumeration value="tL"/> + <xsd:enumeration value="tR"/> + <xsd:enumeration value="radial"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_NodeHorizontalAlignment" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="l"/> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="r"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_NodeVerticalAlignment" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="t"/> + <xsd:enumeration value="mid"/> + <xsd:enumeration value="b"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FallbackDimension" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="1D"/> + <xsd:enumeration value="2D"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextDirection" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="fromT"/> + <xsd:enumeration value="fromB"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PyramidAccentPosition" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="bef"/> + <xsd:enumeration value="aft"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PyramidAccentTextMargin" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="step"/> + <xsd:enumeration value="stack"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextBlockDirection" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="horz"/> + <xsd:enumeration value="vert"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextAnchorHorizontal" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="ctr"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextAnchorVertical" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="t"/> + <xsd:enumeration value="mid"/> + <xsd:enumeration value="b"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_DiagramTextAlignment" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="l"/> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="r"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_AutoTextRotation" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="upr"/> + <xsd:enumeration value="grav"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_GrowDirection" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="tL"/> + <xsd:enumeration value="tR"/> + <xsd:enumeration value="bL"/> + <xsd:enumeration value="bR"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FlowDirection" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="row"/> + <xsd:enumeration value="col"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ContinueDirection" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="revDir"/> + <xsd:enumeration value="sameDir"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Breakpoint" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="endCnv"/> + <xsd:enumeration value="bal"/> + <xsd:enumeration value="fixed"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Offset" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="off"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_HierarchyAlignment" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="tL"/> + <xsd:enumeration value="tR"/> + <xsd:enumeration value="tCtrCh"/> + <xsd:enumeration value="tCtrDes"/> + <xsd:enumeration value="bL"/> + <xsd:enumeration value="bR"/> + <xsd:enumeration value="bCtrCh"/> + <xsd:enumeration value="bCtrDes"/> + <xsd:enumeration value="lT"/> + <xsd:enumeration value="lB"/> + <xsd:enumeration value="lCtrCh"/> + <xsd:enumeration value="lCtrDes"/> + <xsd:enumeration value="rT"/> + <xsd:enumeration value="rB"/> + <xsd:enumeration value="rCtrCh"/> + <xsd:enumeration value="rCtrDes"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FunctionValue" final="restriction"> + <xsd:union + memberTypes="xsd:int xsd:boolean ST_Direction ST_HierBranchStyle ST_AnimOneStr ST_AnimLvlStr ST_ResizeHandlesStr" + /> + </xsd:simpleType> + <xsd:simpleType name="ST_VariableType" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="orgChart"/> + <xsd:enumeration value="chMax"/> + <xsd:enumeration value="chPref"/> + <xsd:enumeration value="bulEnabled"/> + <xsd:enumeration value="dir"/> + <xsd:enumeration value="hierBranch"/> + <xsd:enumeration value="animOne"/> + <xsd:enumeration value="animLvl"/> + <xsd:enumeration value="resizeHandles"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FunctionArgument" final="restriction"> + <xsd:union memberTypes="ST_VariableType"/> + </xsd:simpleType> + <xsd:simpleType name="ST_OutputShapeType" final="restriction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="conn"/> + </xsd:restriction> + </xsd:simpleType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd new file mode 100644 index 0000000..687eea8 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas" + xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" + xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + elementFormDefault="qualified" + targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas"> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main" + schemaLocation="dml-main.xsd"/> + <xsd:element name="lockedCanvas" type="a:CT_GvmlGroupShape"/> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd new file mode 100644 index 0000000..6ac81b0 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd @@ -0,0 +1,3081 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + xmlns="http://schemas.openxmlformats.org/drawingml/2006/main" + targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/main" + elementFormDefault="qualified"> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + schemaLocation="shared-relationshipReference.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + schemaLocation="shared-commonSimpleTypes.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/diagram" + schemaLocation="dml-diagram.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/chart" + schemaLocation="dml-chart.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/picture" + schemaLocation="dml-picture.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas" + schemaLocation="dml-lockedCanvas.xsd"/> + <xsd:complexType name="CT_AudioFile"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute ref="r:link" use="required"/> + <xsd:attribute name="contentType" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_VideoFile"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute ref="r:link" use="required"/> + <xsd:attribute name="contentType" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_QuickTimeFile"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute ref="r:link" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_AudioCDTime"> + <xsd:attribute name="track" type="xsd:unsignedByte" use="required"/> + <xsd:attribute name="time" type="xsd:unsignedInt" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_AudioCD"> + <xsd:sequence> + <xsd:element name="st" type="CT_AudioCDTime" minOccurs="1" maxOccurs="1"/> + <xsd:element name="end" type="CT_AudioCDTime" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_Media"> + <xsd:choice> + <xsd:element name="audioCd" type="CT_AudioCD"/> + <xsd:element name="wavAudioFile" type="CT_EmbeddedWAVAudioFile"/> + <xsd:element name="audioFile" type="CT_AudioFile"/> + <xsd:element name="videoFile" type="CT_VideoFile"/> + <xsd:element name="quickTimeFile" type="CT_QuickTimeFile"/> + </xsd:choice> + </xsd:group> + <xsd:element name="videoFile" type="CT_VideoFile"/> + <xsd:simpleType name="ST_StyleMatrixColumnIndex"> + <xsd:restriction base="xsd:unsignedInt"/> + </xsd:simpleType> + <xsd:simpleType name="ST_FontCollectionIndex"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="major"/> + <xsd:enumeration value="minor"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ColorSchemeIndex"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="dk1"/> + <xsd:enumeration value="lt1"/> + <xsd:enumeration value="dk2"/> + <xsd:enumeration value="lt2"/> + <xsd:enumeration value="accent1"/> + <xsd:enumeration value="accent2"/> + <xsd:enumeration value="accent3"/> + <xsd:enumeration value="accent4"/> + <xsd:enumeration value="accent5"/> + <xsd:enumeration value="accent6"/> + <xsd:enumeration value="hlink"/> + <xsd:enumeration value="folHlink"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_ColorScheme"> + <xsd:sequence> + <xsd:element name="dk1" type="CT_Color" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lt1" type="CT_Color" minOccurs="1" maxOccurs="1"/> + <xsd:element name="dk2" type="CT_Color" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lt2" type="CT_Color" minOccurs="1" maxOccurs="1"/> + <xsd:element name="accent1" type="CT_Color" minOccurs="1" maxOccurs="1"/> + <xsd:element name="accent2" type="CT_Color" minOccurs="1" maxOccurs="1"/> + <xsd:element name="accent3" type="CT_Color" minOccurs="1" maxOccurs="1"/> + <xsd:element name="accent4" type="CT_Color" minOccurs="1" maxOccurs="1"/> + <xsd:element name="accent5" type="CT_Color" minOccurs="1" maxOccurs="1"/> + <xsd:element name="accent6" type="CT_Color" minOccurs="1" maxOccurs="1"/> + <xsd:element name="hlink" type="CT_Color" minOccurs="1" maxOccurs="1"/> + <xsd:element name="folHlink" type="CT_Color" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomColor"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="optional" default=""/> + </xsd:complexType> + <xsd:complexType name="CT_SupplementalFont"> + <xsd:attribute name="script" type="xsd:string" use="required"/> + <xsd:attribute name="typeface" type="ST_TextTypeface" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomColorList"> + <xsd:sequence> + <xsd:element name="custClr" type="CT_CustomColor" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_FontCollection"> + <xsd:sequence> + <xsd:element name="latin" type="CT_TextFont" minOccurs="1" maxOccurs="1"/> + <xsd:element name="ea" type="CT_TextFont" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cs" type="CT_TextFont" minOccurs="1" maxOccurs="1"/> + <xsd:element name="font" type="CT_SupplementalFont" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_EffectStyleItem"> + <xsd:sequence> + <xsd:group ref="EG_EffectProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="scene3d" type="CT_Scene3D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sp3d" type="CT_Shape3D" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_FontScheme"> + <xsd:sequence> + <xsd:element name="majorFont" type="CT_FontCollection" minOccurs="1" maxOccurs="1"/> + <xsd:element name="minorFont" type="CT_FontCollection" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_FillStyleList"> + <xsd:sequence> + <xsd:group ref="EG_FillProperties" minOccurs="3" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_LineStyleList"> + <xsd:sequence> + <xsd:element name="ln" type="CT_LineProperties" minOccurs="3" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_EffectStyleList"> + <xsd:sequence> + <xsd:element name="effectStyle" type="CT_EffectStyleItem" minOccurs="3" maxOccurs="unbounded" + /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_BackgroundFillStyleList"> + <xsd:sequence> + <xsd:group ref="EG_FillProperties" minOccurs="3" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_StyleMatrix"> + <xsd:sequence> + <xsd:element name="fillStyleLst" type="CT_FillStyleList" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lnStyleLst" type="CT_LineStyleList" minOccurs="1" maxOccurs="1"/> + <xsd:element name="effectStyleLst" type="CT_EffectStyleList" minOccurs="1" maxOccurs="1"/> + <xsd:element name="bgFillStyleLst" type="CT_BackgroundFillStyleList" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="optional" default=""/> + </xsd:complexType> + <xsd:complexType name="CT_BaseStyles"> + <xsd:sequence> + <xsd:element name="clrScheme" type="CT_ColorScheme" minOccurs="1" maxOccurs="1"/> + <xsd:element name="fontScheme" type="CT_FontScheme" minOccurs="1" maxOccurs="1"/> + <xsd:element name="fmtScheme" type="CT_StyleMatrix" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_OfficeArtExtension"> + <xsd:sequence> + <xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="uri" type="xsd:token" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_Coordinate"> + <xsd:union memberTypes="ST_CoordinateUnqualified s:ST_UniversalMeasure"/> + </xsd:simpleType> + <xsd:simpleType name="ST_CoordinateUnqualified"> + <xsd:restriction base="xsd:long"> + <xsd:minInclusive value="-27273042329600"/> + <xsd:maxInclusive value="27273042316900"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Coordinate32"> + <xsd:union memberTypes="ST_Coordinate32Unqualified s:ST_UniversalMeasure"/> + </xsd:simpleType> + <xsd:simpleType name="ST_Coordinate32Unqualified"> + <xsd:restriction base="xsd:int"/> + </xsd:simpleType> + <xsd:simpleType name="ST_PositiveCoordinate"> + <xsd:restriction base="xsd:long"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="27273042316900"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PositiveCoordinate32"> + <xsd:restriction base="ST_Coordinate32Unqualified"> + <xsd:minInclusive value="0"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Angle"> + <xsd:restriction base="xsd:int"/> + </xsd:simpleType> + <xsd:complexType name="CT_Angle"> + <xsd:attribute name="val" type="ST_Angle" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_FixedAngle"> + <xsd:restriction base="ST_Angle"> + <xsd:minExclusive value="-5400000"/> + <xsd:maxExclusive value="5400000"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PositiveFixedAngle"> + <xsd:restriction base="ST_Angle"> + <xsd:minInclusive value="0"/> + <xsd:maxExclusive value="21600000"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PositiveFixedAngle"> + <xsd:attribute name="val" type="ST_PositiveFixedAngle" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_Percentage"> + <xsd:union memberTypes="ST_PercentageDecimal s:ST_Percentage"/> + </xsd:simpleType> + <xsd:simpleType name="ST_PercentageDecimal"> + <xsd:restriction base="xsd:int"/> + </xsd:simpleType> + <xsd:complexType name="CT_Percentage"> + <xsd:attribute name="val" type="ST_Percentage" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_PositivePercentage"> + <xsd:union memberTypes="ST_PositivePercentageDecimal s:ST_PositivePercentage"/> + </xsd:simpleType> + <xsd:simpleType name="ST_PositivePercentageDecimal"> + <xsd:restriction base="ST_PercentageDecimal"> + <xsd:minInclusive value="0"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PositivePercentage"> + <xsd:attribute name="val" type="ST_PositivePercentage" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_FixedPercentage"> + <xsd:union memberTypes="ST_FixedPercentageDecimal s:ST_FixedPercentage"/> + </xsd:simpleType> + <xsd:simpleType name="ST_FixedPercentageDecimal"> + <xsd:restriction base="ST_PercentageDecimal"> + <xsd:minInclusive value="-100000"/> + <xsd:maxInclusive value="100000"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_FixedPercentage"> + <xsd:attribute name="val" type="ST_FixedPercentage" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_PositiveFixedPercentage"> + <xsd:union memberTypes="ST_PositiveFixedPercentageDecimal s:ST_PositiveFixedPercentage"/> + </xsd:simpleType> + <xsd:simpleType name="ST_PositiveFixedPercentageDecimal"> + <xsd:restriction base="ST_PercentageDecimal"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="100000"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PositiveFixedPercentage"> + <xsd:attribute name="val" type="ST_PositiveFixedPercentage" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Ratio"> + <xsd:attribute name="n" type="xsd:long" use="required"/> + <xsd:attribute name="d" type="xsd:long" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Point2D"> + <xsd:attribute name="x" type="ST_Coordinate" use="required"/> + <xsd:attribute name="y" type="ST_Coordinate" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_PositiveSize2D"> + <xsd:attribute name="cx" type="ST_PositiveCoordinate" use="required"/> + <xsd:attribute name="cy" type="ST_PositiveCoordinate" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_ComplementTransform"/> + <xsd:complexType name="CT_InverseTransform"/> + <xsd:complexType name="CT_GrayscaleTransform"/> + <xsd:complexType name="CT_GammaTransform"/> + <xsd:complexType name="CT_InverseGammaTransform"/> + <xsd:group name="EG_ColorTransform"> + <xsd:choice> + <xsd:element name="tint" type="CT_PositiveFixedPercentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="shade" type="CT_PositiveFixedPercentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="comp" type="CT_ComplementTransform" minOccurs="1" maxOccurs="1"/> + <xsd:element name="inv" type="CT_InverseTransform" minOccurs="1" maxOccurs="1"/> + <xsd:element name="gray" type="CT_GrayscaleTransform" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alpha" type="CT_PositiveFixedPercentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaOff" type="CT_FixedPercentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaMod" type="CT_PositivePercentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="hue" type="CT_PositiveFixedAngle" minOccurs="1" maxOccurs="1"/> + <xsd:element name="hueOff" type="CT_Angle" minOccurs="1" maxOccurs="1"/> + <xsd:element name="hueMod" type="CT_PositivePercentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="sat" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="satOff" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="satMod" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lum" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lumOff" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lumMod" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="red" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="redOff" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="redMod" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="green" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="greenOff" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="greenMod" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="blue" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="blueOff" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="blueMod" type="CT_Percentage" minOccurs="1" maxOccurs="1"/> + <xsd:element name="gamma" type="CT_GammaTransform" minOccurs="1" maxOccurs="1"/> + <xsd:element name="invGamma" type="CT_InverseGammaTransform" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_ScRgbColor"> + <xsd:sequence> + <xsd:group ref="EG_ColorTransform" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="r" type="ST_Percentage" use="required"/> + <xsd:attribute name="g" type="ST_Percentage" use="required"/> + <xsd:attribute name="b" type="ST_Percentage" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SRgbColor"> + <xsd:sequence> + <xsd:group ref="EG_ColorTransform" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="val" type="s:ST_HexColorRGB" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_HslColor"> + <xsd:sequence> + <xsd:group ref="EG_ColorTransform" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="hue" type="ST_PositiveFixedAngle" use="required"/> + <xsd:attribute name="sat" type="ST_Percentage" use="required"/> + <xsd:attribute name="lum" type="ST_Percentage" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_SystemColorVal"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="scrollBar"/> + <xsd:enumeration value="background"/> + <xsd:enumeration value="activeCaption"/> + <xsd:enumeration value="inactiveCaption"/> + <xsd:enumeration value="menu"/> + <xsd:enumeration value="window"/> + <xsd:enumeration value="windowFrame"/> + <xsd:enumeration value="menuText"/> + <xsd:enumeration value="windowText"/> + <xsd:enumeration value="captionText"/> + <xsd:enumeration value="activeBorder"/> + <xsd:enumeration value="inactiveBorder"/> + <xsd:enumeration value="appWorkspace"/> + <xsd:enumeration value="highlight"/> + <xsd:enumeration value="highlightText"/> + <xsd:enumeration value="btnFace"/> + <xsd:enumeration value="btnShadow"/> + <xsd:enumeration value="grayText"/> + <xsd:enumeration value="btnText"/> + <xsd:enumeration value="inactiveCaptionText"/> + <xsd:enumeration value="btnHighlight"/> + <xsd:enumeration value="3dDkShadow"/> + <xsd:enumeration value="3dLight"/> + <xsd:enumeration value="infoText"/> + <xsd:enumeration value="infoBk"/> + <xsd:enumeration value="hotLight"/> + <xsd:enumeration value="gradientActiveCaption"/> + <xsd:enumeration value="gradientInactiveCaption"/> + <xsd:enumeration value="menuHighlight"/> + <xsd:enumeration value="menuBar"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SystemColor"> + <xsd:sequence> + <xsd:group ref="EG_ColorTransform" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="val" type="ST_SystemColorVal" use="required"/> + <xsd:attribute name="lastClr" type="s:ST_HexColorRGB" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_SchemeColorVal"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="bg1"/> + <xsd:enumeration value="tx1"/> + <xsd:enumeration value="bg2"/> + <xsd:enumeration value="tx2"/> + <xsd:enumeration value="accent1"/> + <xsd:enumeration value="accent2"/> + <xsd:enumeration value="accent3"/> + <xsd:enumeration value="accent4"/> + <xsd:enumeration value="accent5"/> + <xsd:enumeration value="accent6"/> + <xsd:enumeration value="hlink"/> + <xsd:enumeration value="folHlink"/> + <xsd:enumeration value="phClr"/> + <xsd:enumeration value="dk1"/> + <xsd:enumeration value="lt1"/> + <xsd:enumeration value="dk2"/> + <xsd:enumeration value="lt2"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SchemeColor"> + <xsd:sequence> + <xsd:group ref="EG_ColorTransform" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="val" type="ST_SchemeColorVal" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_PresetColorVal"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="aliceBlue"/> + <xsd:enumeration value="antiqueWhite"/> + <xsd:enumeration value="aqua"/> + <xsd:enumeration value="aquamarine"/> + <xsd:enumeration value="azure"/> + <xsd:enumeration value="beige"/> + <xsd:enumeration value="bisque"/> + <xsd:enumeration value="black"/> + <xsd:enumeration value="blanchedAlmond"/> + <xsd:enumeration value="blue"/> + <xsd:enumeration value="blueViolet"/> + <xsd:enumeration value="brown"/> + <xsd:enumeration value="burlyWood"/> + <xsd:enumeration value="cadetBlue"/> + <xsd:enumeration value="chartreuse"/> + <xsd:enumeration value="chocolate"/> + <xsd:enumeration value="coral"/> + <xsd:enumeration value="cornflowerBlue"/> + <xsd:enumeration value="cornsilk"/> + <xsd:enumeration value="crimson"/> + <xsd:enumeration value="cyan"/> + <xsd:enumeration value="darkBlue"/> + <xsd:enumeration value="darkCyan"/> + <xsd:enumeration value="darkGoldenrod"/> + <xsd:enumeration value="darkGray"/> + <xsd:enumeration value="darkGrey"/> + <xsd:enumeration value="darkGreen"/> + <xsd:enumeration value="darkKhaki"/> + <xsd:enumeration value="darkMagenta"/> + <xsd:enumeration value="darkOliveGreen"/> + <xsd:enumeration value="darkOrange"/> + <xsd:enumeration value="darkOrchid"/> + <xsd:enumeration value="darkRed"/> + <xsd:enumeration value="darkSalmon"/> + <xsd:enumeration value="darkSeaGreen"/> + <xsd:enumeration value="darkSlateBlue"/> + <xsd:enumeration value="darkSlateGray"/> + <xsd:enumeration value="darkSlateGrey"/> + <xsd:enumeration value="darkTurquoise"/> + <xsd:enumeration value="darkViolet"/> + <xsd:enumeration value="dkBlue"/> + <xsd:enumeration value="dkCyan"/> + <xsd:enumeration value="dkGoldenrod"/> + <xsd:enumeration value="dkGray"/> + <xsd:enumeration value="dkGrey"/> + <xsd:enumeration value="dkGreen"/> + <xsd:enumeration value="dkKhaki"/> + <xsd:enumeration value="dkMagenta"/> + <xsd:enumeration value="dkOliveGreen"/> + <xsd:enumeration value="dkOrange"/> + <xsd:enumeration value="dkOrchid"/> + <xsd:enumeration value="dkRed"/> + <xsd:enumeration value="dkSalmon"/> + <xsd:enumeration value="dkSeaGreen"/> + <xsd:enumeration value="dkSlateBlue"/> + <xsd:enumeration value="dkSlateGray"/> + <xsd:enumeration value="dkSlateGrey"/> + <xsd:enumeration value="dkTurquoise"/> + <xsd:enumeration value="dkViolet"/> + <xsd:enumeration value="deepPink"/> + <xsd:enumeration value="deepSkyBlue"/> + <xsd:enumeration value="dimGray"/> + <xsd:enumeration value="dimGrey"/> + <xsd:enumeration value="dodgerBlue"/> + <xsd:enumeration value="firebrick"/> + <xsd:enumeration value="floralWhite"/> + <xsd:enumeration value="forestGreen"/> + <xsd:enumeration value="fuchsia"/> + <xsd:enumeration value="gainsboro"/> + <xsd:enumeration value="ghostWhite"/> + <xsd:enumeration value="gold"/> + <xsd:enumeration value="goldenrod"/> + <xsd:enumeration value="gray"/> + <xsd:enumeration value="grey"/> + <xsd:enumeration value="green"/> + <xsd:enumeration value="greenYellow"/> + <xsd:enumeration value="honeydew"/> + <xsd:enumeration value="hotPink"/> + <xsd:enumeration value="indianRed"/> + <xsd:enumeration value="indigo"/> + <xsd:enumeration value="ivory"/> + <xsd:enumeration value="khaki"/> + <xsd:enumeration value="lavender"/> + <xsd:enumeration value="lavenderBlush"/> + <xsd:enumeration value="lawnGreen"/> + <xsd:enumeration value="lemonChiffon"/> + <xsd:enumeration value="lightBlue"/> + <xsd:enumeration value="lightCoral"/> + <xsd:enumeration value="lightCyan"/> + <xsd:enumeration value="lightGoldenrodYellow"/> + <xsd:enumeration value="lightGray"/> + <xsd:enumeration value="lightGrey"/> + <xsd:enumeration value="lightGreen"/> + <xsd:enumeration value="lightPink"/> + <xsd:enumeration value="lightSalmon"/> + <xsd:enumeration value="lightSeaGreen"/> + <xsd:enumeration value="lightSkyBlue"/> + <xsd:enumeration value="lightSlateGray"/> + <xsd:enumeration value="lightSlateGrey"/> + <xsd:enumeration value="lightSteelBlue"/> + <xsd:enumeration value="lightYellow"/> + <xsd:enumeration value="ltBlue"/> + <xsd:enumeration value="ltCoral"/> + <xsd:enumeration value="ltCyan"/> + <xsd:enumeration value="ltGoldenrodYellow"/> + <xsd:enumeration value="ltGray"/> + <xsd:enumeration value="ltGrey"/> + <xsd:enumeration value="ltGreen"/> + <xsd:enumeration value="ltPink"/> + <xsd:enumeration value="ltSalmon"/> + <xsd:enumeration value="ltSeaGreen"/> + <xsd:enumeration value="ltSkyBlue"/> + <xsd:enumeration value="ltSlateGray"/> + <xsd:enumeration value="ltSlateGrey"/> + <xsd:enumeration value="ltSteelBlue"/> + <xsd:enumeration value="ltYellow"/> + <xsd:enumeration value="lime"/> + <xsd:enumeration value="limeGreen"/> + <xsd:enumeration value="linen"/> + <xsd:enumeration value="magenta"/> + <xsd:enumeration value="maroon"/> + <xsd:enumeration value="medAquamarine"/> + <xsd:enumeration value="medBlue"/> + <xsd:enumeration value="medOrchid"/> + <xsd:enumeration value="medPurple"/> + <xsd:enumeration value="medSeaGreen"/> + <xsd:enumeration value="medSlateBlue"/> + <xsd:enumeration value="medSpringGreen"/> + <xsd:enumeration value="medTurquoise"/> + <xsd:enumeration value="medVioletRed"/> + <xsd:enumeration value="mediumAquamarine"/> + <xsd:enumeration value="mediumBlue"/> + <xsd:enumeration value="mediumOrchid"/> + <xsd:enumeration value="mediumPurple"/> + <xsd:enumeration value="mediumSeaGreen"/> + <xsd:enumeration value="mediumSlateBlue"/> + <xsd:enumeration value="mediumSpringGreen"/> + <xsd:enumeration value="mediumTurquoise"/> + <xsd:enumeration value="mediumVioletRed"/> + <xsd:enumeration value="midnightBlue"/> + <xsd:enumeration value="mintCream"/> + <xsd:enumeration value="mistyRose"/> + <xsd:enumeration value="moccasin"/> + <xsd:enumeration value="navajoWhite"/> + <xsd:enumeration value="navy"/> + <xsd:enumeration value="oldLace"/> + <xsd:enumeration value="olive"/> + <xsd:enumeration value="oliveDrab"/> + <xsd:enumeration value="orange"/> + <xsd:enumeration value="orangeRed"/> + <xsd:enumeration value="orchid"/> + <xsd:enumeration value="paleGoldenrod"/> + <xsd:enumeration value="paleGreen"/> + <xsd:enumeration value="paleTurquoise"/> + <xsd:enumeration value="paleVioletRed"/> + <xsd:enumeration value="papayaWhip"/> + <xsd:enumeration value="peachPuff"/> + <xsd:enumeration value="peru"/> + <xsd:enumeration value="pink"/> + <xsd:enumeration value="plum"/> + <xsd:enumeration value="powderBlue"/> + <xsd:enumeration value="purple"/> + <xsd:enumeration value="red"/> + <xsd:enumeration value="rosyBrown"/> + <xsd:enumeration value="royalBlue"/> + <xsd:enumeration value="saddleBrown"/> + <xsd:enumeration value="salmon"/> + <xsd:enumeration value="sandyBrown"/> + <xsd:enumeration value="seaGreen"/> + <xsd:enumeration value="seaShell"/> + <xsd:enumeration value="sienna"/> + <xsd:enumeration value="silver"/> + <xsd:enumeration value="skyBlue"/> + <xsd:enumeration value="slateBlue"/> + <xsd:enumeration value="slateGray"/> + <xsd:enumeration value="slateGrey"/> + <xsd:enumeration value="snow"/> + <xsd:enumeration value="springGreen"/> + <xsd:enumeration value="steelBlue"/> + <xsd:enumeration value="tan"/> + <xsd:enumeration value="teal"/> + <xsd:enumeration value="thistle"/> + <xsd:enumeration value="tomato"/> + <xsd:enumeration value="turquoise"/> + <xsd:enumeration value="violet"/> + <xsd:enumeration value="wheat"/> + <xsd:enumeration value="white"/> + <xsd:enumeration value="whiteSmoke"/> + <xsd:enumeration value="yellow"/> + <xsd:enumeration value="yellowGreen"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PresetColor"> + <xsd:sequence> + <xsd:group ref="EG_ColorTransform" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="val" type="ST_PresetColorVal" use="required"/> + </xsd:complexType> + <xsd:group name="EG_OfficeArtExtensionList"> + <xsd:sequence> + <xsd:element name="ext" type="CT_OfficeArtExtension" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_OfficeArtExtensionList"> + <xsd:sequence> + <xsd:group ref="EG_OfficeArtExtensionList" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Scale2D"> + <xsd:sequence> + <xsd:element name="sx" type="CT_Ratio" minOccurs="1" maxOccurs="1"/> + <xsd:element name="sy" type="CT_Ratio" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Transform2D"> + <xsd:sequence> + <xsd:element name="off" type="CT_Point2D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ext" type="CT_PositiveSize2D" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="rot" type="ST_Angle" use="optional" default="0"/> + <xsd:attribute name="flipH" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="flipV" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_GroupTransform2D"> + <xsd:sequence> + <xsd:element name="off" type="CT_Point2D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ext" type="CT_PositiveSize2D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="chOff" type="CT_Point2D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="chExt" type="CT_PositiveSize2D" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="rot" type="ST_Angle" use="optional" default="0"/> + <xsd:attribute name="flipH" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="flipV" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_Point3D"> + <xsd:attribute name="x" type="ST_Coordinate" use="required"/> + <xsd:attribute name="y" type="ST_Coordinate" use="required"/> + <xsd:attribute name="z" type="ST_Coordinate" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Vector3D"> + <xsd:attribute name="dx" type="ST_Coordinate" use="required"/> + <xsd:attribute name="dy" type="ST_Coordinate" use="required"/> + <xsd:attribute name="dz" type="ST_Coordinate" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SphereCoords"> + <xsd:attribute name="lat" type="ST_PositiveFixedAngle" use="required"/> + <xsd:attribute name="lon" type="ST_PositiveFixedAngle" use="required"/> + <xsd:attribute name="rev" type="ST_PositiveFixedAngle" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_RelativeRect"> + <xsd:attribute name="l" type="ST_Percentage" use="optional" default="0%"/> + <xsd:attribute name="t" type="ST_Percentage" use="optional" default="0%"/> + <xsd:attribute name="r" type="ST_Percentage" use="optional" default="0%"/> + <xsd:attribute name="b" type="ST_Percentage" use="optional" default="0%"/> + </xsd:complexType> + <xsd:simpleType name="ST_RectAlignment"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="tl"/> + <xsd:enumeration value="t"/> + <xsd:enumeration value="tr"/> + <xsd:enumeration value="l"/> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="r"/> + <xsd:enumeration value="bl"/> + <xsd:enumeration value="b"/> + <xsd:enumeration value="br"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:group name="EG_ColorChoice"> + <xsd:choice> + <xsd:element name="scrgbClr" type="CT_ScRgbColor" minOccurs="1" maxOccurs="1"/> + <xsd:element name="srgbClr" type="CT_SRgbColor" minOccurs="1" maxOccurs="1"/> + <xsd:element name="hslClr" type="CT_HslColor" minOccurs="1" maxOccurs="1"/> + <xsd:element name="sysClr" type="CT_SystemColor" minOccurs="1" maxOccurs="1"/> + <xsd:element name="schemeClr" type="CT_SchemeColor" minOccurs="1" maxOccurs="1"/> + <xsd:element name="prstClr" type="CT_PresetColor" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_Color"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ColorMRU"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_BlackWhiteMode"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="clr"/> + <xsd:enumeration value="auto"/> + <xsd:enumeration value="gray"/> + <xsd:enumeration value="ltGray"/> + <xsd:enumeration value="invGray"/> + <xsd:enumeration value="grayWhite"/> + <xsd:enumeration value="blackGray"/> + <xsd:enumeration value="blackWhite"/> + <xsd:enumeration value="black"/> + <xsd:enumeration value="white"/> + <xsd:enumeration value="hidden"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:attributeGroup name="AG_Blob"> + <xsd:attribute ref="r:embed" use="optional" default=""/> + <xsd:attribute ref="r:link" use="optional" default=""/> + </xsd:attributeGroup> + <xsd:complexType name="CT_EmbeddedWAVAudioFile"> + <xsd:attribute ref="r:embed" use="required"/> + <xsd:attribute name="name" type="xsd:string" use="optional" default=""/> + </xsd:complexType> + <xsd:complexType name="CT_Hyperlink"> + <xsd:sequence> + <xsd:element name="snd" type="CT_EmbeddedWAVAudioFile" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute ref="r:id" use="optional"/> + <xsd:attribute name="invalidUrl" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="action" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="tgtFrame" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="tooltip" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="history" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="highlightClick" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="endSnd" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:simpleType name="ST_DrawingElementId"> + <xsd:restriction base="xsd:unsignedInt"/> + </xsd:simpleType> + <xsd:attributeGroup name="AG_Locking"> + <xsd:attribute name="noGrp" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noSelect" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noRot" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noChangeAspect" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noMove" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noResize" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noEditPoints" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noAdjustHandles" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noChangeArrowheads" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noChangeShapeType" type="xsd:boolean" use="optional" default="false"/> + </xsd:attributeGroup> + <xsd:complexType name="CT_ConnectorLocking"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_Locking"/> + </xsd:complexType> + <xsd:complexType name="CT_ShapeLocking"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_Locking"/> + <xsd:attribute name="noTextEdit" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_PictureLocking"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_Locking"/> + <xsd:attribute name="noCrop" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_GroupLocking"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="noGrp" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noUngrp" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noSelect" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noRot" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noChangeAspect" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noMove" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noResize" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_GraphicalObjectFrameLocking"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="noGrp" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noDrilldown" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noSelect" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noChangeAspect" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noMove" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="noResize" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_ContentPartLocking"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_Locking"/> + </xsd:complexType> + <xsd:complexType name="CT_NonVisualDrawingProps"> + <xsd:sequence> + <xsd:element name="hlinkClick" type="CT_Hyperlink" minOccurs="0" maxOccurs="1"/> + <xsd:element name="hlinkHover" type="CT_Hyperlink" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="id" type="ST_DrawingElementId" use="required"/> + <xsd:attribute name="name" type="xsd:string" use="required"/> + <xsd:attribute name="descr" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="hidden" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="title" type="xsd:string" use="optional" default=""/> + </xsd:complexType> + <xsd:complexType name="CT_NonVisualDrawingShapeProps"> + <xsd:sequence> + <xsd:element name="spLocks" type="CT_ShapeLocking" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="txBox" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_NonVisualConnectorProperties"> + <xsd:sequence> + <xsd:element name="cxnSpLocks" type="CT_ConnectorLocking" minOccurs="0" maxOccurs="1"/> + <xsd:element name="stCxn" type="CT_Connection" minOccurs="0" maxOccurs="1"/> + <xsd:element name="endCxn" type="CT_Connection" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_NonVisualPictureProperties"> + <xsd:sequence> + <xsd:element name="picLocks" type="CT_PictureLocking" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="preferRelativeResize" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_NonVisualGroupDrawingShapeProps"> + <xsd:sequence> + <xsd:element name="grpSpLocks" type="CT_GroupLocking" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_NonVisualGraphicFrameProperties"> + <xsd:sequence> + <xsd:element name="graphicFrameLocks" type="CT_GraphicalObjectFrameLocking" minOccurs="0" + maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_NonVisualContentPartProperties"> + <xsd:sequence> + <xsd:element name="cpLocks" type="CT_ContentPartLocking" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="isComment" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_GraphicalObjectData"> + <xsd:sequence> + <xsd:any minOccurs="0" maxOccurs="unbounded" processContents="strict"/> + </xsd:sequence> + <xsd:attribute name="uri" type="xsd:token" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_GraphicalObject"> + <xsd:sequence> + <xsd:element name="graphicData" type="CT_GraphicalObjectData"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="graphic" type="CT_GraphicalObject"/> + <xsd:simpleType name="ST_ChartBuildStep"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="category"/> + <xsd:enumeration value="ptInCategory"/> + <xsd:enumeration value="series"/> + <xsd:enumeration value="ptInSeries"/> + <xsd:enumeration value="allPts"/> + <xsd:enumeration value="gridLegend"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_DgmBuildStep"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="sp"/> + <xsd:enumeration value="bg"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_AnimationDgmElement"> + <xsd:attribute name="id" type="s:ST_Guid" use="optional" + default="{00000000-0000-0000-0000-000000000000}"/> + <xsd:attribute name="bldStep" type="ST_DgmBuildStep" use="optional" default="sp"/> + </xsd:complexType> + <xsd:complexType name="CT_AnimationChartElement"> + <xsd:attribute name="seriesIdx" type="xsd:int" use="optional" default="-1"/> + <xsd:attribute name="categoryIdx" type="xsd:int" use="optional" default="-1"/> + <xsd:attribute name="bldStep" type="ST_ChartBuildStep" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_AnimationElementChoice"> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="dgm" type="CT_AnimationDgmElement"/> + <xsd:element name="chart" type="CT_AnimationChartElement"/> + </xsd:choice> + </xsd:complexType> + <xsd:simpleType name="ST_AnimationBuildType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="allAtOnce"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_AnimationDgmOnlyBuildType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="one"/> + <xsd:enumeration value="lvlOne"/> + <xsd:enumeration value="lvlAtOnce"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_AnimationDgmBuildType"> + <xsd:union memberTypes="ST_AnimationBuildType ST_AnimationDgmOnlyBuildType"/> + </xsd:simpleType> + <xsd:complexType name="CT_AnimationDgmBuildProperties"> + <xsd:attribute name="bld" type="ST_AnimationDgmBuildType" use="optional" default="allAtOnce"/> + <xsd:attribute name="rev" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:simpleType name="ST_AnimationChartOnlyBuildType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="series"/> + <xsd:enumeration value="category"/> + <xsd:enumeration value="seriesEl"/> + <xsd:enumeration value="categoryEl"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_AnimationChartBuildType"> + <xsd:union memberTypes="ST_AnimationBuildType ST_AnimationChartOnlyBuildType"/> + </xsd:simpleType> + <xsd:complexType name="CT_AnimationChartBuildProperties"> + <xsd:attribute name="bld" type="ST_AnimationChartBuildType" use="optional" default="allAtOnce"/> + <xsd:attribute name="animBg" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_AnimationGraphicalObjectBuildProperties"> + <xsd:choice> + <xsd:element name="bldDgm" type="CT_AnimationDgmBuildProperties"/> + <xsd:element name="bldChart" type="CT_AnimationChartBuildProperties"/> + </xsd:choice> + </xsd:complexType> + <xsd:complexType name="CT_BackgroundFormatting"> + <xsd:sequence> + <xsd:group ref="EG_FillProperties" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_EffectProperties" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_WholeE2oFormatting"> + <xsd:sequence> + <xsd:element name="ln" type="CT_LineProperties" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_EffectProperties" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GvmlUseShapeRectangle"/> + <xsd:complexType name="CT_GvmlTextShape"> + <xsd:sequence> + <xsd:element name="txBody" type="CT_TextBody" minOccurs="1" maxOccurs="1"/> + <xsd:choice> + <xsd:element name="useSpRect" type="CT_GvmlUseShapeRectangle" minOccurs="1" maxOccurs="1"/> + <xsd:element name="xfrm" type="CT_Transform2D" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GvmlShapeNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvSpPr" type="CT_NonVisualDrawingShapeProps" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GvmlShape"> + <xsd:sequence> + <xsd:element name="nvSpPr" type="CT_GvmlShapeNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="txSp" type="CT_GvmlTextShape" minOccurs="0" maxOccurs="1"/> + <xsd:element name="style" type="CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GvmlConnectorNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvCxnSpPr" type="CT_NonVisualConnectorProperties" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GvmlConnector"> + <xsd:sequence> + <xsd:element name="nvCxnSpPr" type="CT_GvmlConnectorNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="style" type="CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GvmlPictureNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvPicPr" type="CT_NonVisualPictureProperties" minOccurs="1" maxOccurs="1" + /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GvmlPicture"> + <xsd:sequence> + <xsd:element name="nvPicPr" type="CT_GvmlPictureNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="blipFill" type="CT_BlipFillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="style" type="CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GvmlGraphicFrameNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvGraphicFramePr" type="CT_NonVisualGraphicFrameProperties" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GvmlGraphicalObjectFrame"> + <xsd:sequence> + <xsd:element name="nvGraphicFramePr" type="CT_GvmlGraphicFrameNonVisual" minOccurs="1" + maxOccurs="1"/> + <xsd:element ref="graphic" minOccurs="1" maxOccurs="1"/> + <xsd:element name="xfrm" type="CT_Transform2D" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GvmlGroupShapeNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvGrpSpPr" type="CT_NonVisualGroupDrawingShapeProps" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GvmlGroupShape"> + <xsd:sequence> + <xsd:element name="nvGrpSpPr" type="CT_GvmlGroupShapeNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="grpSpPr" type="CT_GroupShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="txSp" type="CT_GvmlTextShape"/> + <xsd:element name="sp" type="CT_GvmlShape"/> + <xsd:element name="cxnSp" type="CT_GvmlConnector"/> + <xsd:element name="pic" type="CT_GvmlPicture"/> + <xsd:element name="graphicFrame" type="CT_GvmlGraphicalObjectFrame"/> + <xsd:element name="grpSp" type="CT_GvmlGroupShape"/> + </xsd:choice> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_PresetCameraType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="legacyObliqueTopLeft"/> + <xsd:enumeration value="legacyObliqueTop"/> + <xsd:enumeration value="legacyObliqueTopRight"/> + <xsd:enumeration value="legacyObliqueLeft"/> + <xsd:enumeration value="legacyObliqueFront"/> + <xsd:enumeration value="legacyObliqueRight"/> + <xsd:enumeration value="legacyObliqueBottomLeft"/> + <xsd:enumeration value="legacyObliqueBottom"/> + <xsd:enumeration value="legacyObliqueBottomRight"/> + <xsd:enumeration value="legacyPerspectiveTopLeft"/> + <xsd:enumeration value="legacyPerspectiveTop"/> + <xsd:enumeration value="legacyPerspectiveTopRight"/> + <xsd:enumeration value="legacyPerspectiveLeft"/> + <xsd:enumeration value="legacyPerspectiveFront"/> + <xsd:enumeration value="legacyPerspectiveRight"/> + <xsd:enumeration value="legacyPerspectiveBottomLeft"/> + <xsd:enumeration value="legacyPerspectiveBottom"/> + <xsd:enumeration value="legacyPerspectiveBottomRight"/> + <xsd:enumeration value="orthographicFront"/> + <xsd:enumeration value="isometricTopUp"/> + <xsd:enumeration value="isometricTopDown"/> + <xsd:enumeration value="isometricBottomUp"/> + <xsd:enumeration value="isometricBottomDown"/> + <xsd:enumeration value="isometricLeftUp"/> + <xsd:enumeration value="isometricLeftDown"/> + <xsd:enumeration value="isometricRightUp"/> + <xsd:enumeration value="isometricRightDown"/> + <xsd:enumeration value="isometricOffAxis1Left"/> + <xsd:enumeration value="isometricOffAxis1Right"/> + <xsd:enumeration value="isometricOffAxis1Top"/> + <xsd:enumeration value="isometricOffAxis2Left"/> + <xsd:enumeration value="isometricOffAxis2Right"/> + <xsd:enumeration value="isometricOffAxis2Top"/> + <xsd:enumeration value="isometricOffAxis3Left"/> + <xsd:enumeration value="isometricOffAxis3Right"/> + <xsd:enumeration value="isometricOffAxis3Bottom"/> + <xsd:enumeration value="isometricOffAxis4Left"/> + <xsd:enumeration value="isometricOffAxis4Right"/> + <xsd:enumeration value="isometricOffAxis4Bottom"/> + <xsd:enumeration value="obliqueTopLeft"/> + <xsd:enumeration value="obliqueTop"/> + <xsd:enumeration value="obliqueTopRight"/> + <xsd:enumeration value="obliqueLeft"/> + <xsd:enumeration value="obliqueRight"/> + <xsd:enumeration value="obliqueBottomLeft"/> + <xsd:enumeration value="obliqueBottom"/> + <xsd:enumeration value="obliqueBottomRight"/> + <xsd:enumeration value="perspectiveFront"/> + <xsd:enumeration value="perspectiveLeft"/> + <xsd:enumeration value="perspectiveRight"/> + <xsd:enumeration value="perspectiveAbove"/> + <xsd:enumeration value="perspectiveBelow"/> + <xsd:enumeration value="perspectiveAboveLeftFacing"/> + <xsd:enumeration value="perspectiveAboveRightFacing"/> + <xsd:enumeration value="perspectiveContrastingLeftFacing"/> + <xsd:enumeration value="perspectiveContrastingRightFacing"/> + <xsd:enumeration value="perspectiveHeroicLeftFacing"/> + <xsd:enumeration value="perspectiveHeroicRightFacing"/> + <xsd:enumeration value="perspectiveHeroicExtremeLeftFacing"/> + <xsd:enumeration value="perspectiveHeroicExtremeRightFacing"/> + <xsd:enumeration value="perspectiveRelaxed"/> + <xsd:enumeration value="perspectiveRelaxedModerately"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FOVAngle"> + <xsd:restriction base="ST_Angle"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="10800000"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Camera"> + <xsd:sequence> + <xsd:element name="rot" type="CT_SphereCoords" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="prst" type="ST_PresetCameraType" use="required"/> + <xsd:attribute name="fov" type="ST_FOVAngle" use="optional"/> + <xsd:attribute name="zoom" type="ST_PositivePercentage" use="optional" default="100%"/> + </xsd:complexType> + <xsd:simpleType name="ST_LightRigDirection"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="tl"/> + <xsd:enumeration value="t"/> + <xsd:enumeration value="tr"/> + <xsd:enumeration value="l"/> + <xsd:enumeration value="r"/> + <xsd:enumeration value="bl"/> + <xsd:enumeration value="b"/> + <xsd:enumeration value="br"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_LightRigType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="legacyFlat1"/> + <xsd:enumeration value="legacyFlat2"/> + <xsd:enumeration value="legacyFlat3"/> + <xsd:enumeration value="legacyFlat4"/> + <xsd:enumeration value="legacyNormal1"/> + <xsd:enumeration value="legacyNormal2"/> + <xsd:enumeration value="legacyNormal3"/> + <xsd:enumeration value="legacyNormal4"/> + <xsd:enumeration value="legacyHarsh1"/> + <xsd:enumeration value="legacyHarsh2"/> + <xsd:enumeration value="legacyHarsh3"/> + <xsd:enumeration value="legacyHarsh4"/> + <xsd:enumeration value="threePt"/> + <xsd:enumeration value="balanced"/> + <xsd:enumeration value="soft"/> + <xsd:enumeration value="harsh"/> + <xsd:enumeration value="flood"/> + <xsd:enumeration value="contrasting"/> + <xsd:enumeration value="morning"/> + <xsd:enumeration value="sunrise"/> + <xsd:enumeration value="sunset"/> + <xsd:enumeration value="chilly"/> + <xsd:enumeration value="freezing"/> + <xsd:enumeration value="flat"/> + <xsd:enumeration value="twoPt"/> + <xsd:enumeration value="glow"/> + <xsd:enumeration value="brightRoom"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_LightRig"> + <xsd:sequence> + <xsd:element name="rot" type="CT_SphereCoords" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="rig" type="ST_LightRigType" use="required"/> + <xsd:attribute name="dir" type="ST_LightRigDirection" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Scene3D"> + <xsd:sequence> + <xsd:element name="camera" type="CT_Camera" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lightRig" type="CT_LightRig" minOccurs="1" maxOccurs="1"/> + <xsd:element name="backdrop" type="CT_Backdrop" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Backdrop"> + <xsd:sequence> + <xsd:element name="anchor" type="CT_Point3D" minOccurs="1" maxOccurs="1"/> + <xsd:element name="norm" type="CT_Vector3D" minOccurs="1" maxOccurs="1"/> + <xsd:element name="up" type="CT_Vector3D" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_BevelPresetType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="relaxedInset"/> + <xsd:enumeration value="circle"/> + <xsd:enumeration value="slope"/> + <xsd:enumeration value="cross"/> + <xsd:enumeration value="angle"/> + <xsd:enumeration value="softRound"/> + <xsd:enumeration value="convex"/> + <xsd:enumeration value="coolSlant"/> + <xsd:enumeration value="divot"/> + <xsd:enumeration value="riblet"/> + <xsd:enumeration value="hardEdge"/> + <xsd:enumeration value="artDeco"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Bevel"> + <xsd:attribute name="w" type="ST_PositiveCoordinate" use="optional" default="76200"/> + <xsd:attribute name="h" type="ST_PositiveCoordinate" use="optional" default="76200"/> + <xsd:attribute name="prst" type="ST_BevelPresetType" use="optional" default="circle"/> + </xsd:complexType> + <xsd:simpleType name="ST_PresetMaterialType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="legacyMatte"/> + <xsd:enumeration value="legacyPlastic"/> + <xsd:enumeration value="legacyMetal"/> + <xsd:enumeration value="legacyWireframe"/> + <xsd:enumeration value="matte"/> + <xsd:enumeration value="plastic"/> + <xsd:enumeration value="metal"/> + <xsd:enumeration value="warmMatte"/> + <xsd:enumeration value="translucentPowder"/> + <xsd:enumeration value="powder"/> + <xsd:enumeration value="dkEdge"/> + <xsd:enumeration value="softEdge"/> + <xsd:enumeration value="clear"/> + <xsd:enumeration value="flat"/> + <xsd:enumeration value="softmetal"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Shape3D"> + <xsd:sequence> + <xsd:element name="bevelT" type="CT_Bevel" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bevelB" type="CT_Bevel" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extrusionClr" type="CT_Color" minOccurs="0" maxOccurs="1"/> + <xsd:element name="contourClr" type="CT_Color" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="z" type="ST_Coordinate" use="optional" default="0"/> + <xsd:attribute name="extrusionH" type="ST_PositiveCoordinate" use="optional" default="0"/> + <xsd:attribute name="contourW" type="ST_PositiveCoordinate" use="optional" default="0"/> + <xsd:attribute name="prstMaterial" type="ST_PresetMaterialType" use="optional" + default="warmMatte"/> + </xsd:complexType> + <xsd:complexType name="CT_FlatText"> + <xsd:attribute name="z" type="ST_Coordinate" use="optional" default="0"/> + </xsd:complexType> + <xsd:group name="EG_Text3D"> + <xsd:choice> + <xsd:element name="sp3d" type="CT_Shape3D" minOccurs="1" maxOccurs="1"/> + <xsd:element name="flatTx" type="CT_FlatText" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_AlphaBiLevelEffect"> + <xsd:attribute name="thresh" type="ST_PositiveFixedPercentage" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_AlphaCeilingEffect"/> + <xsd:complexType name="CT_AlphaFloorEffect"/> + <xsd:complexType name="CT_AlphaInverseEffect"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_AlphaModulateFixedEffect"> + <xsd:attribute name="amt" type="ST_PositivePercentage" use="optional" default="100%"/> + </xsd:complexType> + <xsd:complexType name="CT_AlphaOutsetEffect"> + <xsd:attribute name="rad" type="ST_Coordinate" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_AlphaReplaceEffect"> + <xsd:attribute name="a" type="ST_PositiveFixedPercentage" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_BiLevelEffect"> + <xsd:attribute name="thresh" type="ST_PositiveFixedPercentage" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_BlurEffect"> + <xsd:attribute name="rad" type="ST_PositiveCoordinate" use="optional" default="0"/> + <xsd:attribute name="grow" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_ColorChangeEffect"> + <xsd:sequence> + <xsd:element name="clrFrom" type="CT_Color" minOccurs="1" maxOccurs="1"/> + <xsd:element name="clrTo" type="CT_Color" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="useA" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_ColorReplaceEffect"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DuotoneEffect"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice" minOccurs="2" maxOccurs="2"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GlowEffect"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="rad" type="ST_PositiveCoordinate" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_GrayscaleEffect"/> + <xsd:complexType name="CT_HSLEffect"> + <xsd:attribute name="hue" type="ST_PositiveFixedAngle" use="optional" default="0"/> + <xsd:attribute name="sat" type="ST_FixedPercentage" use="optional" default="0%"/> + <xsd:attribute name="lum" type="ST_FixedPercentage" use="optional" default="0%"/> + </xsd:complexType> + <xsd:complexType name="CT_InnerShadowEffect"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="blurRad" type="ST_PositiveCoordinate" use="optional" default="0"/> + <xsd:attribute name="dist" type="ST_PositiveCoordinate" use="optional" default="0"/> + <xsd:attribute name="dir" type="ST_PositiveFixedAngle" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_LuminanceEffect"> + <xsd:attribute name="bright" type="ST_FixedPercentage" use="optional" default="0%"/> + <xsd:attribute name="contrast" type="ST_FixedPercentage" use="optional" default="0%"/> + </xsd:complexType> + <xsd:complexType name="CT_OuterShadowEffect"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="blurRad" type="ST_PositiveCoordinate" use="optional" default="0"/> + <xsd:attribute name="dist" type="ST_PositiveCoordinate" use="optional" default="0"/> + <xsd:attribute name="dir" type="ST_PositiveFixedAngle" use="optional" default="0"/> + <xsd:attribute name="sx" type="ST_Percentage" use="optional" default="100%"/> + <xsd:attribute name="sy" type="ST_Percentage" use="optional" default="100%"/> + <xsd:attribute name="kx" type="ST_FixedAngle" use="optional" default="0"/> + <xsd:attribute name="ky" type="ST_FixedAngle" use="optional" default="0"/> + <xsd:attribute name="algn" type="ST_RectAlignment" use="optional" default="b"/> + <xsd:attribute name="rotWithShape" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:simpleType name="ST_PresetShadowVal"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="shdw1"/> + <xsd:enumeration value="shdw2"/> + <xsd:enumeration value="shdw3"/> + <xsd:enumeration value="shdw4"/> + <xsd:enumeration value="shdw5"/> + <xsd:enumeration value="shdw6"/> + <xsd:enumeration value="shdw7"/> + <xsd:enumeration value="shdw8"/> + <xsd:enumeration value="shdw9"/> + <xsd:enumeration value="shdw10"/> + <xsd:enumeration value="shdw11"/> + <xsd:enumeration value="shdw12"/> + <xsd:enumeration value="shdw13"/> + <xsd:enumeration value="shdw14"/> + <xsd:enumeration value="shdw15"/> + <xsd:enumeration value="shdw16"/> + <xsd:enumeration value="shdw17"/> + <xsd:enumeration value="shdw18"/> + <xsd:enumeration value="shdw19"/> + <xsd:enumeration value="shdw20"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PresetShadowEffect"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="prst" type="ST_PresetShadowVal" use="required"/> + <xsd:attribute name="dist" type="ST_PositiveCoordinate" use="optional" default="0"/> + <xsd:attribute name="dir" type="ST_PositiveFixedAngle" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_ReflectionEffect"> + <xsd:attribute name="blurRad" type="ST_PositiveCoordinate" use="optional" default="0"/> + <xsd:attribute name="stA" type="ST_PositiveFixedPercentage" use="optional" default="100%"/> + <xsd:attribute name="stPos" type="ST_PositiveFixedPercentage" use="optional" default="0%"/> + <xsd:attribute name="endA" type="ST_PositiveFixedPercentage" use="optional" default="0%"/> + <xsd:attribute name="endPos" type="ST_PositiveFixedPercentage" use="optional" default="100%"/> + <xsd:attribute name="dist" type="ST_PositiveCoordinate" use="optional" default="0"/> + <xsd:attribute name="dir" type="ST_PositiveFixedAngle" use="optional" default="0"/> + <xsd:attribute name="fadeDir" type="ST_PositiveFixedAngle" use="optional" default="5400000"/> + <xsd:attribute name="sx" type="ST_Percentage" use="optional" default="100%"/> + <xsd:attribute name="sy" type="ST_Percentage" use="optional" default="100%"/> + <xsd:attribute name="kx" type="ST_FixedAngle" use="optional" default="0"/> + <xsd:attribute name="ky" type="ST_FixedAngle" use="optional" default="0"/> + <xsd:attribute name="algn" type="ST_RectAlignment" use="optional" default="b"/> + <xsd:attribute name="rotWithShape" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_RelativeOffsetEffect"> + <xsd:attribute name="tx" type="ST_Percentage" use="optional" default="0%"/> + <xsd:attribute name="ty" type="ST_Percentage" use="optional" default="0%"/> + </xsd:complexType> + <xsd:complexType name="CT_SoftEdgesEffect"> + <xsd:attribute name="rad" type="ST_PositiveCoordinate" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TintEffect"> + <xsd:attribute name="hue" type="ST_PositiveFixedAngle" use="optional" default="0"/> + <xsd:attribute name="amt" type="ST_FixedPercentage" use="optional" default="0%"/> + </xsd:complexType> + <xsd:complexType name="CT_TransformEffect"> + <xsd:attribute name="sx" type="ST_Percentage" use="optional" default="100%"/> + <xsd:attribute name="sy" type="ST_Percentage" use="optional" default="100%"/> + <xsd:attribute name="kx" type="ST_FixedAngle" use="optional" default="0"/> + <xsd:attribute name="ky" type="ST_FixedAngle" use="optional" default="0"/> + <xsd:attribute name="tx" type="ST_Coordinate" use="optional" default="0"/> + <xsd:attribute name="ty" type="ST_Coordinate" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_NoFillProperties"/> + <xsd:complexType name="CT_SolidColorFillProperties"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_LinearShadeProperties"> + <xsd:attribute name="ang" type="ST_PositiveFixedAngle" use="optional"/> + <xsd:attribute name="scaled" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_PathShadeType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="shape"/> + <xsd:enumeration value="circle"/> + <xsd:enumeration value="rect"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PathShadeProperties"> + <xsd:sequence> + <xsd:element name="fillToRect" type="CT_RelativeRect" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="path" type="ST_PathShadeType" use="optional"/> + </xsd:complexType> + <xsd:group name="EG_ShadeProperties"> + <xsd:choice> + <xsd:element name="lin" type="CT_LinearShadeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="path" type="CT_PathShadeProperties" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:simpleType name="ST_TileFlipMode"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="x"/> + <xsd:enumeration value="y"/> + <xsd:enumeration value="xy"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_GradientStop"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="pos" type="ST_PositiveFixedPercentage" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_GradientStopList"> + <xsd:sequence> + <xsd:element name="gs" type="CT_GradientStop" minOccurs="2" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GradientFillProperties"> + <xsd:sequence> + <xsd:element name="gsLst" type="CT_GradientStopList" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_ShadeProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tileRect" type="CT_RelativeRect" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="flip" type="ST_TileFlipMode" use="optional" default="none"/> + <xsd:attribute name="rotWithShape" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TileInfoProperties"> + <xsd:attribute name="tx" type="ST_Coordinate" use="optional"/> + <xsd:attribute name="ty" type="ST_Coordinate" use="optional"/> + <xsd:attribute name="sx" type="ST_Percentage" use="optional"/> + <xsd:attribute name="sy" type="ST_Percentage" use="optional"/> + <xsd:attribute name="flip" type="ST_TileFlipMode" use="optional" default="none"/> + <xsd:attribute name="algn" type="ST_RectAlignment" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_StretchInfoProperties"> + <xsd:sequence> + <xsd:element name="fillRect" type="CT_RelativeRect" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_FillModeProperties"> + <xsd:choice> + <xsd:element name="tile" type="CT_TileInfoProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="stretch" type="CT_StretchInfoProperties" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:simpleType name="ST_BlipCompression"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="email"/> + <xsd:enumeration value="screen"/> + <xsd:enumeration value="print"/> + <xsd:enumeration value="hqprint"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Blip"> + <xsd:sequence> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="alphaBiLevel" type="CT_AlphaBiLevelEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaCeiling" type="CT_AlphaCeilingEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaFloor" type="CT_AlphaFloorEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaInv" type="CT_AlphaInverseEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaMod" type="CT_AlphaModulateEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaModFix" type="CT_AlphaModulateFixedEffect" minOccurs="1" + maxOccurs="1"/> + <xsd:element name="alphaRepl" type="CT_AlphaReplaceEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="biLevel" type="CT_BiLevelEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="blur" type="CT_BlurEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="clrChange" type="CT_ColorChangeEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="clrRepl" type="CT_ColorReplaceEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="duotone" type="CT_DuotoneEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="fillOverlay" type="CT_FillOverlayEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="grayscl" type="CT_GrayscaleEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="hsl" type="CT_HSLEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lum" type="CT_LuminanceEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="tint" type="CT_TintEffect" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_Blob"/> + <xsd:attribute name="cstate" type="ST_BlipCompression" use="optional" default="none"/> + </xsd:complexType> + <xsd:complexType name="CT_BlipFillProperties"> + <xsd:sequence> + <xsd:element name="blip" type="CT_Blip" minOccurs="0" maxOccurs="1"/> + <xsd:element name="srcRect" type="CT_RelativeRect" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_FillModeProperties" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="dpi" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="rotWithShape" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_PresetPatternVal"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="pct5"/> + <xsd:enumeration value="pct10"/> + <xsd:enumeration value="pct20"/> + <xsd:enumeration value="pct25"/> + <xsd:enumeration value="pct30"/> + <xsd:enumeration value="pct40"/> + <xsd:enumeration value="pct50"/> + <xsd:enumeration value="pct60"/> + <xsd:enumeration value="pct70"/> + <xsd:enumeration value="pct75"/> + <xsd:enumeration value="pct80"/> + <xsd:enumeration value="pct90"/> + <xsd:enumeration value="horz"/> + <xsd:enumeration value="vert"/> + <xsd:enumeration value="ltHorz"/> + <xsd:enumeration value="ltVert"/> + <xsd:enumeration value="dkHorz"/> + <xsd:enumeration value="dkVert"/> + <xsd:enumeration value="narHorz"/> + <xsd:enumeration value="narVert"/> + <xsd:enumeration value="dashHorz"/> + <xsd:enumeration value="dashVert"/> + <xsd:enumeration value="cross"/> + <xsd:enumeration value="dnDiag"/> + <xsd:enumeration value="upDiag"/> + <xsd:enumeration value="ltDnDiag"/> + <xsd:enumeration value="ltUpDiag"/> + <xsd:enumeration value="dkDnDiag"/> + <xsd:enumeration value="dkUpDiag"/> + <xsd:enumeration value="wdDnDiag"/> + <xsd:enumeration value="wdUpDiag"/> + <xsd:enumeration value="dashDnDiag"/> + <xsd:enumeration value="dashUpDiag"/> + <xsd:enumeration value="diagCross"/> + <xsd:enumeration value="smCheck"/> + <xsd:enumeration value="lgCheck"/> + <xsd:enumeration value="smGrid"/> + <xsd:enumeration value="lgGrid"/> + <xsd:enumeration value="dotGrid"/> + <xsd:enumeration value="smConfetti"/> + <xsd:enumeration value="lgConfetti"/> + <xsd:enumeration value="horzBrick"/> + <xsd:enumeration value="diagBrick"/> + <xsd:enumeration value="solidDmnd"/> + <xsd:enumeration value="openDmnd"/> + <xsd:enumeration value="dotDmnd"/> + <xsd:enumeration value="plaid"/> + <xsd:enumeration value="sphere"/> + <xsd:enumeration value="weave"/> + <xsd:enumeration value="divot"/> + <xsd:enumeration value="shingle"/> + <xsd:enumeration value="wave"/> + <xsd:enumeration value="trellis"/> + <xsd:enumeration value="zigZag"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PatternFillProperties"> + <xsd:sequence> + <xsd:element name="fgClr" type="CT_Color" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bgClr" type="CT_Color" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="prst" type="ST_PresetPatternVal" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_GroupFillProperties"/> + <xsd:group name="EG_FillProperties"> + <xsd:choice> + <xsd:element name="noFill" type="CT_NoFillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="solidFill" type="CT_SolidColorFillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="gradFill" type="CT_GradientFillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="blipFill" type="CT_BlipFillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="pattFill" type="CT_PatternFillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="grpFill" type="CT_GroupFillProperties" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_FillProperties"> + <xsd:sequence> + <xsd:group ref="EG_FillProperties" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_FillEffect"> + <xsd:sequence> + <xsd:group ref="EG_FillProperties" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_BlendMode"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="over"/> + <xsd:enumeration value="mult"/> + <xsd:enumeration value="screen"/> + <xsd:enumeration value="darken"/> + <xsd:enumeration value="lighten"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_FillOverlayEffect"> + <xsd:sequence> + <xsd:group ref="EG_FillProperties" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="blend" type="ST_BlendMode" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_EffectReference"> + <xsd:attribute name="ref" type="xsd:token" use="required"/> + </xsd:complexType> + <xsd:group name="EG_Effect"> + <xsd:choice> + <xsd:element name="cont" type="CT_EffectContainer" minOccurs="1" maxOccurs="1"/> + <xsd:element name="effect" type="CT_EffectReference" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaBiLevel" type="CT_AlphaBiLevelEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaCeiling" type="CT_AlphaCeilingEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaFloor" type="CT_AlphaFloorEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaInv" type="CT_AlphaInverseEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaMod" type="CT_AlphaModulateEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaModFix" type="CT_AlphaModulateFixedEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaOutset" type="CT_AlphaOutsetEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="alphaRepl" type="CT_AlphaReplaceEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="biLevel" type="CT_BiLevelEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="blend" type="CT_BlendEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="blur" type="CT_BlurEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="clrChange" type="CT_ColorChangeEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="clrRepl" type="CT_ColorReplaceEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="duotone" type="CT_DuotoneEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="fill" type="CT_FillEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="fillOverlay" type="CT_FillOverlayEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="glow" type="CT_GlowEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="grayscl" type="CT_GrayscaleEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="hsl" type="CT_HSLEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="innerShdw" type="CT_InnerShadowEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lum" type="CT_LuminanceEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="outerShdw" type="CT_OuterShadowEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="prstShdw" type="CT_PresetShadowEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="reflection" type="CT_ReflectionEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="relOff" type="CT_RelativeOffsetEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="softEdge" type="CT_SoftEdgesEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="tint" type="CT_TintEffect" minOccurs="1" maxOccurs="1"/> + <xsd:element name="xfrm" type="CT_TransformEffect" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:simpleType name="ST_EffectContainerType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="sib"/> + <xsd:enumeration value="tree"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_EffectContainer"> + <xsd:group ref="EG_Effect" minOccurs="0" maxOccurs="unbounded"/> + <xsd:attribute name="type" type="ST_EffectContainerType" use="optional" default="sib"/> + <xsd:attribute name="name" type="xsd:token" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_AlphaModulateEffect"> + <xsd:sequence> + <xsd:element name="cont" type="CT_EffectContainer" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_BlendEffect"> + <xsd:sequence> + <xsd:element name="cont" type="CT_EffectContainer" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="blend" type="ST_BlendMode" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_EffectList"> + <xsd:sequence> + <xsd:element name="blur" type="CT_BlurEffect" minOccurs="0" maxOccurs="1"/> + <xsd:element name="fillOverlay" type="CT_FillOverlayEffect" minOccurs="0" maxOccurs="1"/> + <xsd:element name="glow" type="CT_GlowEffect" minOccurs="0" maxOccurs="1"/> + <xsd:element name="innerShdw" type="CT_InnerShadowEffect" minOccurs="0" maxOccurs="1"/> + <xsd:element name="outerShdw" type="CT_OuterShadowEffect" minOccurs="0" maxOccurs="1"/> + <xsd:element name="prstShdw" type="CT_PresetShadowEffect" minOccurs="0" maxOccurs="1"/> + <xsd:element name="reflection" type="CT_ReflectionEffect" minOccurs="0" maxOccurs="1"/> + <xsd:element name="softEdge" type="CT_SoftEdgesEffect" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_EffectProperties"> + <xsd:choice> + <xsd:element name="effectLst" type="CT_EffectList" minOccurs="1" maxOccurs="1"/> + <xsd:element name="effectDag" type="CT_EffectContainer" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_EffectProperties"> + <xsd:sequence> + <xsd:group ref="EG_EffectProperties" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="blip" type="CT_Blip"/> + <xsd:simpleType name="ST_ShapeType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="line"/> + <xsd:enumeration value="lineInv"/> + <xsd:enumeration value="triangle"/> + <xsd:enumeration value="rtTriangle"/> + <xsd:enumeration value="rect"/> + <xsd:enumeration value="diamond"/> + <xsd:enumeration value="parallelogram"/> + <xsd:enumeration value="trapezoid"/> + <xsd:enumeration value="nonIsoscelesTrapezoid"/> + <xsd:enumeration value="pentagon"/> + <xsd:enumeration value="hexagon"/> + <xsd:enumeration value="heptagon"/> + <xsd:enumeration value="octagon"/> + <xsd:enumeration value="decagon"/> + <xsd:enumeration value="dodecagon"/> + <xsd:enumeration value="star4"/> + <xsd:enumeration value="star5"/> + <xsd:enumeration value="star6"/> + <xsd:enumeration value="star7"/> + <xsd:enumeration value="star8"/> + <xsd:enumeration value="star10"/> + <xsd:enumeration value="star12"/> + <xsd:enumeration value="star16"/> + <xsd:enumeration value="star24"/> + <xsd:enumeration value="star32"/> + <xsd:enumeration value="roundRect"/> + <xsd:enumeration value="round1Rect"/> + <xsd:enumeration value="round2SameRect"/> + <xsd:enumeration value="round2DiagRect"/> + <xsd:enumeration value="snipRoundRect"/> + <xsd:enumeration value="snip1Rect"/> + <xsd:enumeration value="snip2SameRect"/> + <xsd:enumeration value="snip2DiagRect"/> + <xsd:enumeration value="plaque"/> + <xsd:enumeration value="ellipse"/> + <xsd:enumeration value="teardrop"/> + <xsd:enumeration value="homePlate"/> + <xsd:enumeration value="chevron"/> + <xsd:enumeration value="pieWedge"/> + <xsd:enumeration value="pie"/> + <xsd:enumeration value="blockArc"/> + <xsd:enumeration value="donut"/> + <xsd:enumeration value="noSmoking"/> + <xsd:enumeration value="rightArrow"/> + <xsd:enumeration value="leftArrow"/> + <xsd:enumeration value="upArrow"/> + <xsd:enumeration value="downArrow"/> + <xsd:enumeration value="stripedRightArrow"/> + <xsd:enumeration value="notchedRightArrow"/> + <xsd:enumeration value="bentUpArrow"/> + <xsd:enumeration value="leftRightArrow"/> + <xsd:enumeration value="upDownArrow"/> + <xsd:enumeration value="leftUpArrow"/> + <xsd:enumeration value="leftRightUpArrow"/> + <xsd:enumeration value="quadArrow"/> + <xsd:enumeration value="leftArrowCallout"/> + <xsd:enumeration value="rightArrowCallout"/> + <xsd:enumeration value="upArrowCallout"/> + <xsd:enumeration value="downArrowCallout"/> + <xsd:enumeration value="leftRightArrowCallout"/> + <xsd:enumeration value="upDownArrowCallout"/> + <xsd:enumeration value="quadArrowCallout"/> + <xsd:enumeration value="bentArrow"/> + <xsd:enumeration value="uturnArrow"/> + <xsd:enumeration value="circularArrow"/> + <xsd:enumeration value="leftCircularArrow"/> + <xsd:enumeration value="leftRightCircularArrow"/> + <xsd:enumeration value="curvedRightArrow"/> + <xsd:enumeration value="curvedLeftArrow"/> + <xsd:enumeration value="curvedUpArrow"/> + <xsd:enumeration value="curvedDownArrow"/> + <xsd:enumeration value="swooshArrow"/> + <xsd:enumeration value="cube"/> + <xsd:enumeration value="can"/> + <xsd:enumeration value="lightningBolt"/> + <xsd:enumeration value="heart"/> + <xsd:enumeration value="sun"/> + <xsd:enumeration value="moon"/> + <xsd:enumeration value="smileyFace"/> + <xsd:enumeration value="irregularSeal1"/> + <xsd:enumeration value="irregularSeal2"/> + <xsd:enumeration value="foldedCorner"/> + <xsd:enumeration value="bevel"/> + <xsd:enumeration value="frame"/> + <xsd:enumeration value="halfFrame"/> + <xsd:enumeration value="corner"/> + <xsd:enumeration value="diagStripe"/> + <xsd:enumeration value="chord"/> + <xsd:enumeration value="arc"/> + <xsd:enumeration value="leftBracket"/> + <xsd:enumeration value="rightBracket"/> + <xsd:enumeration value="leftBrace"/> + <xsd:enumeration value="rightBrace"/> + <xsd:enumeration value="bracketPair"/> + <xsd:enumeration value="bracePair"/> + <xsd:enumeration value="straightConnector1"/> + <xsd:enumeration value="bentConnector2"/> + <xsd:enumeration value="bentConnector3"/> + <xsd:enumeration value="bentConnector4"/> + <xsd:enumeration value="bentConnector5"/> + <xsd:enumeration value="curvedConnector2"/> + <xsd:enumeration value="curvedConnector3"/> + <xsd:enumeration value="curvedConnector4"/> + <xsd:enumeration value="curvedConnector5"/> + <xsd:enumeration value="callout1"/> + <xsd:enumeration value="callout2"/> + <xsd:enumeration value="callout3"/> + <xsd:enumeration value="accentCallout1"/> + <xsd:enumeration value="accentCallout2"/> + <xsd:enumeration value="accentCallout3"/> + <xsd:enumeration value="borderCallout1"/> + <xsd:enumeration value="borderCallout2"/> + <xsd:enumeration value="borderCallout3"/> + <xsd:enumeration value="accentBorderCallout1"/> + <xsd:enumeration value="accentBorderCallout2"/> + <xsd:enumeration value="accentBorderCallout3"/> + <xsd:enumeration value="wedgeRectCallout"/> + <xsd:enumeration value="wedgeRoundRectCallout"/> + <xsd:enumeration value="wedgeEllipseCallout"/> + <xsd:enumeration value="cloudCallout"/> + <xsd:enumeration value="cloud"/> + <xsd:enumeration value="ribbon"/> + <xsd:enumeration value="ribbon2"/> + <xsd:enumeration value="ellipseRibbon"/> + <xsd:enumeration value="ellipseRibbon2"/> + <xsd:enumeration value="leftRightRibbon"/> + <xsd:enumeration value="verticalScroll"/> + <xsd:enumeration value="horizontalScroll"/> + <xsd:enumeration value="wave"/> + <xsd:enumeration value="doubleWave"/> + <xsd:enumeration value="plus"/> + <xsd:enumeration value="flowChartProcess"/> + <xsd:enumeration value="flowChartDecision"/> + <xsd:enumeration value="flowChartInputOutput"/> + <xsd:enumeration value="flowChartPredefinedProcess"/> + <xsd:enumeration value="flowChartInternalStorage"/> + <xsd:enumeration value="flowChartDocument"/> + <xsd:enumeration value="flowChartMultidocument"/> + <xsd:enumeration value="flowChartTerminator"/> + <xsd:enumeration value="flowChartPreparation"/> + <xsd:enumeration value="flowChartManualInput"/> + <xsd:enumeration value="flowChartManualOperation"/> + <xsd:enumeration value="flowChartConnector"/> + <xsd:enumeration value="flowChartPunchedCard"/> + <xsd:enumeration value="flowChartPunchedTape"/> + <xsd:enumeration value="flowChartSummingJunction"/> + <xsd:enumeration value="flowChartOr"/> + <xsd:enumeration value="flowChartCollate"/> + <xsd:enumeration value="flowChartSort"/> + <xsd:enumeration value="flowChartExtract"/> + <xsd:enumeration value="flowChartMerge"/> + <xsd:enumeration value="flowChartOfflineStorage"/> + <xsd:enumeration value="flowChartOnlineStorage"/> + <xsd:enumeration value="flowChartMagneticTape"/> + <xsd:enumeration value="flowChartMagneticDisk"/> + <xsd:enumeration value="flowChartMagneticDrum"/> + <xsd:enumeration value="flowChartDisplay"/> + <xsd:enumeration value="flowChartDelay"/> + <xsd:enumeration value="flowChartAlternateProcess"/> + <xsd:enumeration value="flowChartOffpageConnector"/> + <xsd:enumeration value="actionButtonBlank"/> + <xsd:enumeration value="actionButtonHome"/> + <xsd:enumeration value="actionButtonHelp"/> + <xsd:enumeration value="actionButtonInformation"/> + <xsd:enumeration value="actionButtonForwardNext"/> + <xsd:enumeration value="actionButtonBackPrevious"/> + <xsd:enumeration value="actionButtonEnd"/> + <xsd:enumeration value="actionButtonBeginning"/> + <xsd:enumeration value="actionButtonReturn"/> + <xsd:enumeration value="actionButtonDocument"/> + <xsd:enumeration value="actionButtonSound"/> + <xsd:enumeration value="actionButtonMovie"/> + <xsd:enumeration value="gear6"/> + <xsd:enumeration value="gear9"/> + <xsd:enumeration value="funnel"/> + <xsd:enumeration value="mathPlus"/> + <xsd:enumeration value="mathMinus"/> + <xsd:enumeration value="mathMultiply"/> + <xsd:enumeration value="mathDivide"/> + <xsd:enumeration value="mathEqual"/> + <xsd:enumeration value="mathNotEqual"/> + <xsd:enumeration value="cornerTabs"/> + <xsd:enumeration value="squareTabs"/> + <xsd:enumeration value="plaqueTabs"/> + <xsd:enumeration value="chartX"/> + <xsd:enumeration value="chartStar"/> + <xsd:enumeration value="chartPlus"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextShapeType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="textNoShape"/> + <xsd:enumeration value="textPlain"/> + <xsd:enumeration value="textStop"/> + <xsd:enumeration value="textTriangle"/> + <xsd:enumeration value="textTriangleInverted"/> + <xsd:enumeration value="textChevron"/> + <xsd:enumeration value="textChevronInverted"/> + <xsd:enumeration value="textRingInside"/> + <xsd:enumeration value="textRingOutside"/> + <xsd:enumeration value="textArchUp"/> + <xsd:enumeration value="textArchDown"/> + <xsd:enumeration value="textCircle"/> + <xsd:enumeration value="textButton"/> + <xsd:enumeration value="textArchUpPour"/> + <xsd:enumeration value="textArchDownPour"/> + <xsd:enumeration value="textCirclePour"/> + <xsd:enumeration value="textButtonPour"/> + <xsd:enumeration value="textCurveUp"/> + <xsd:enumeration value="textCurveDown"/> + <xsd:enumeration value="textCanUp"/> + <xsd:enumeration value="textCanDown"/> + <xsd:enumeration value="textWave1"/> + <xsd:enumeration value="textWave2"/> + <xsd:enumeration value="textDoubleWave1"/> + <xsd:enumeration value="textWave4"/> + <xsd:enumeration value="textInflate"/> + <xsd:enumeration value="textDeflate"/> + <xsd:enumeration value="textInflateBottom"/> + <xsd:enumeration value="textDeflateBottom"/> + <xsd:enumeration value="textInflateTop"/> + <xsd:enumeration value="textDeflateTop"/> + <xsd:enumeration value="textDeflateInflate"/> + <xsd:enumeration value="textDeflateInflateDeflate"/> + <xsd:enumeration value="textFadeRight"/> + <xsd:enumeration value="textFadeLeft"/> + <xsd:enumeration value="textFadeUp"/> + <xsd:enumeration value="textFadeDown"/> + <xsd:enumeration value="textSlantUp"/> + <xsd:enumeration value="textSlantDown"/> + <xsd:enumeration value="textCascadeUp"/> + <xsd:enumeration value="textCascadeDown"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_GeomGuideName"> + <xsd:restriction base="xsd:token"/> + </xsd:simpleType> + <xsd:simpleType name="ST_GeomGuideFormula"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:complexType name="CT_GeomGuide"> + <xsd:attribute name="name" type="ST_GeomGuideName" use="required"/> + <xsd:attribute name="fmla" type="ST_GeomGuideFormula" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_GeomGuideList"> + <xsd:sequence> + <xsd:element name="gd" type="CT_GeomGuide" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_AdjCoordinate"> + <xsd:union memberTypes="ST_Coordinate ST_GeomGuideName"/> + </xsd:simpleType> + <xsd:simpleType name="ST_AdjAngle"> + <xsd:union memberTypes="ST_Angle ST_GeomGuideName"/> + </xsd:simpleType> + <xsd:complexType name="CT_AdjPoint2D"> + <xsd:attribute name="x" type="ST_AdjCoordinate" use="required"/> + <xsd:attribute name="y" type="ST_AdjCoordinate" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_GeomRect"> + <xsd:attribute name="l" type="ST_AdjCoordinate" use="required"/> + <xsd:attribute name="t" type="ST_AdjCoordinate" use="required"/> + <xsd:attribute name="r" type="ST_AdjCoordinate" use="required"/> + <xsd:attribute name="b" type="ST_AdjCoordinate" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_XYAdjustHandle"> + <xsd:sequence> + <xsd:element name="pos" type="CT_AdjPoint2D" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="gdRefX" type="ST_GeomGuideName" use="optional"/> + <xsd:attribute name="minX" type="ST_AdjCoordinate" use="optional"/> + <xsd:attribute name="maxX" type="ST_AdjCoordinate" use="optional"/> + <xsd:attribute name="gdRefY" type="ST_GeomGuideName" use="optional"/> + <xsd:attribute name="minY" type="ST_AdjCoordinate" use="optional"/> + <xsd:attribute name="maxY" type="ST_AdjCoordinate" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_PolarAdjustHandle"> + <xsd:sequence> + <xsd:element name="pos" type="CT_AdjPoint2D" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="gdRefR" type="ST_GeomGuideName" use="optional"/> + <xsd:attribute name="minR" type="ST_AdjCoordinate" use="optional"/> + <xsd:attribute name="maxR" type="ST_AdjCoordinate" use="optional"/> + <xsd:attribute name="gdRefAng" type="ST_GeomGuideName" use="optional"/> + <xsd:attribute name="minAng" type="ST_AdjAngle" use="optional"/> + <xsd:attribute name="maxAng" type="ST_AdjAngle" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_ConnectionSite"> + <xsd:sequence> + <xsd:element name="pos" type="CT_AdjPoint2D" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="ang" type="ST_AdjAngle" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_AdjustHandleList"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="ahXY" type="CT_XYAdjustHandle" minOccurs="1" maxOccurs="1"/> + <xsd:element name="ahPolar" type="CT_PolarAdjustHandle" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:complexType> + <xsd:complexType name="CT_ConnectionSiteList"> + <xsd:sequence> + <xsd:element name="cxn" type="CT_ConnectionSite" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Connection"> + <xsd:attribute name="id" type="ST_DrawingElementId" use="required"/> + <xsd:attribute name="idx" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Path2DMoveTo"> + <xsd:sequence> + <xsd:element name="pt" type="CT_AdjPoint2D" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Path2DLineTo"> + <xsd:sequence> + <xsd:element name="pt" type="CT_AdjPoint2D" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Path2DArcTo"> + <xsd:attribute name="wR" type="ST_AdjCoordinate" use="required"/> + <xsd:attribute name="hR" type="ST_AdjCoordinate" use="required"/> + <xsd:attribute name="stAng" type="ST_AdjAngle" use="required"/> + <xsd:attribute name="swAng" type="ST_AdjAngle" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Path2DQuadBezierTo"> + <xsd:sequence> + <xsd:element name="pt" type="CT_AdjPoint2D" minOccurs="2" maxOccurs="2"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Path2DCubicBezierTo"> + <xsd:sequence> + <xsd:element name="pt" type="CT_AdjPoint2D" minOccurs="3" maxOccurs="3"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Path2DClose"/> + <xsd:simpleType name="ST_PathFillMode"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="norm"/> + <xsd:enumeration value="lighten"/> + <xsd:enumeration value="lightenLess"/> + <xsd:enumeration value="darken"/> + <xsd:enumeration value="darkenLess"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Path2D"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="close" type="CT_Path2DClose" minOccurs="1" maxOccurs="1"/> + <xsd:element name="moveTo" type="CT_Path2DMoveTo" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lnTo" type="CT_Path2DLineTo" minOccurs="1" maxOccurs="1"/> + <xsd:element name="arcTo" type="CT_Path2DArcTo" minOccurs="1" maxOccurs="1"/> + <xsd:element name="quadBezTo" type="CT_Path2DQuadBezierTo" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cubicBezTo" type="CT_Path2DCubicBezierTo" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + <xsd:attribute name="w" type="ST_PositiveCoordinate" use="optional" default="0"/> + <xsd:attribute name="h" type="ST_PositiveCoordinate" use="optional" default="0"/> + <xsd:attribute name="fill" type="ST_PathFillMode" use="optional" default="norm"/> + <xsd:attribute name="stroke" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="extrusionOk" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_Path2DList"> + <xsd:sequence> + <xsd:element name="path" type="CT_Path2D" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PresetGeometry2D"> + <xsd:sequence> + <xsd:element name="avLst" type="CT_GeomGuideList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="prst" type="ST_ShapeType" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_PresetTextShape"> + <xsd:sequence> + <xsd:element name="avLst" type="CT_GeomGuideList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="prst" type="ST_TextShapeType" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomGeometry2D"> + <xsd:sequence> + <xsd:element name="avLst" type="CT_GeomGuideList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="gdLst" type="CT_GeomGuideList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ahLst" type="CT_AdjustHandleList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cxnLst" type="CT_ConnectionSiteList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="rect" type="CT_GeomRect" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pathLst" type="CT_Path2DList" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_Geometry"> + <xsd:choice> + <xsd:element name="custGeom" type="CT_CustomGeometry2D" minOccurs="1" maxOccurs="1"/> + <xsd:element name="prstGeom" type="CT_PresetGeometry2D" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:group name="EG_TextGeometry"> + <xsd:choice> + <xsd:element name="custGeom" type="CT_CustomGeometry2D" minOccurs="1" maxOccurs="1"/> + <xsd:element name="prstTxWarp" type="CT_PresetTextShape" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:simpleType name="ST_LineEndType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="triangle"/> + <xsd:enumeration value="stealth"/> + <xsd:enumeration value="diamond"/> + <xsd:enumeration value="oval"/> + <xsd:enumeration value="arrow"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_LineEndWidth"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="sm"/> + <xsd:enumeration value="med"/> + <xsd:enumeration value="lg"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_LineEndLength"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="sm"/> + <xsd:enumeration value="med"/> + <xsd:enumeration value="lg"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_LineEndProperties"> + <xsd:attribute name="type" type="ST_LineEndType" use="optional" default="none"/> + <xsd:attribute name="w" type="ST_LineEndWidth" use="optional"/> + <xsd:attribute name="len" type="ST_LineEndLength" use="optional"/> + </xsd:complexType> + <xsd:group name="EG_LineFillProperties"> + <xsd:choice> + <xsd:element name="noFill" type="CT_NoFillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="solidFill" type="CT_SolidColorFillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="gradFill" type="CT_GradientFillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="pattFill" type="CT_PatternFillProperties" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_LineJoinBevel"/> + <xsd:complexType name="CT_LineJoinRound"/> + <xsd:complexType name="CT_LineJoinMiterProperties"> + <xsd:attribute name="lim" type="ST_PositivePercentage" use="optional"/> + </xsd:complexType> + <xsd:group name="EG_LineJoinProperties"> + <xsd:choice> + <xsd:element name="round" type="CT_LineJoinRound" minOccurs="1" maxOccurs="1"/> + <xsd:element name="bevel" type="CT_LineJoinBevel" minOccurs="1" maxOccurs="1"/> + <xsd:element name="miter" type="CT_LineJoinMiterProperties" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:simpleType name="ST_PresetLineDashVal"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="solid"/> + <xsd:enumeration value="dot"/> + <xsd:enumeration value="dash"/> + <xsd:enumeration value="lgDash"/> + <xsd:enumeration value="dashDot"/> + <xsd:enumeration value="lgDashDot"/> + <xsd:enumeration value="lgDashDotDot"/> + <xsd:enumeration value="sysDash"/> + <xsd:enumeration value="sysDot"/> + <xsd:enumeration value="sysDashDot"/> + <xsd:enumeration value="sysDashDotDot"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PresetLineDashProperties"> + <xsd:attribute name="val" type="ST_PresetLineDashVal" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_DashStop"> + <xsd:attribute name="d" type="ST_PositivePercentage" use="required"/> + <xsd:attribute name="sp" type="ST_PositivePercentage" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_DashStopList"> + <xsd:sequence> + <xsd:element name="ds" type="CT_DashStop" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_LineDashProperties"> + <xsd:choice> + <xsd:element name="prstDash" type="CT_PresetLineDashProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="custDash" type="CT_DashStopList" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:simpleType name="ST_LineCap"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="rnd"/> + <xsd:enumeration value="sq"/> + <xsd:enumeration value="flat"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_LineWidth"> + <xsd:restriction base="ST_Coordinate32Unqualified"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="20116800"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PenAlignment"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="in"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_CompoundLine"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="sng"/> + <xsd:enumeration value="dbl"/> + <xsd:enumeration value="thickThin"/> + <xsd:enumeration value="thinThick"/> + <xsd:enumeration value="tri"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_LineProperties"> + <xsd:sequence> + <xsd:group ref="EG_LineFillProperties" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_LineDashProperties" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_LineJoinProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="headEnd" type="CT_LineEndProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tailEnd" type="CT_LineEndProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="w" type="ST_LineWidth" use="optional"/> + <xsd:attribute name="cap" type="ST_LineCap" use="optional"/> + <xsd:attribute name="cmpd" type="ST_CompoundLine" use="optional"/> + <xsd:attribute name="algn" type="ST_PenAlignment" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_ShapeID"> + <xsd:restriction base="xsd:token"/> + </xsd:simpleType> + <xsd:complexType name="CT_ShapeProperties"> + <xsd:sequence> + <xsd:element name="xfrm" type="CT_Transform2D" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_Geometry" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_FillProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ln" type="CT_LineProperties" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_EffectProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="scene3d" type="CT_Scene3D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sp3d" type="CT_Shape3D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="bwMode" type="ST_BlackWhiteMode" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_GroupShapeProperties"> + <xsd:sequence> + <xsd:element name="xfrm" type="CT_GroupTransform2D" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_FillProperties" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_EffectProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="scene3d" type="CT_Scene3D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="bwMode" type="ST_BlackWhiteMode" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_StyleMatrixReference"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="idx" type="ST_StyleMatrixColumnIndex" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_FontReference"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="idx" type="ST_FontCollectionIndex" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_ShapeStyle"> + <xsd:sequence> + <xsd:element name="lnRef" type="CT_StyleMatrixReference" minOccurs="1" maxOccurs="1"/> + <xsd:element name="fillRef" type="CT_StyleMatrixReference" minOccurs="1" maxOccurs="1"/> + <xsd:element name="effectRef" type="CT_StyleMatrixReference" minOccurs="1" maxOccurs="1"/> + <xsd:element name="fontRef" type="CT_FontReference" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DefaultShapeDefinition"> + <xsd:sequence> + <xsd:element name="spPr" type="CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="bodyPr" type="CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lstStyle" type="CT_TextListStyle" minOccurs="1" maxOccurs="1"/> + <xsd:element name="style" type="CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ObjectStyleDefaults"> + <xsd:sequence> + <xsd:element name="spDef" type="CT_DefaultShapeDefinition" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lnDef" type="CT_DefaultShapeDefinition" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txDef" type="CT_DefaultShapeDefinition" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_EmptyElement"/> + <xsd:complexType name="CT_ColorMapping"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="bg1" type="ST_ColorSchemeIndex" use="required"/> + <xsd:attribute name="tx1" type="ST_ColorSchemeIndex" use="required"/> + <xsd:attribute name="bg2" type="ST_ColorSchemeIndex" use="required"/> + <xsd:attribute name="tx2" type="ST_ColorSchemeIndex" use="required"/> + <xsd:attribute name="accent1" type="ST_ColorSchemeIndex" use="required"/> + <xsd:attribute name="accent2" type="ST_ColorSchemeIndex" use="required"/> + <xsd:attribute name="accent3" type="ST_ColorSchemeIndex" use="required"/> + <xsd:attribute name="accent4" type="ST_ColorSchemeIndex" use="required"/> + <xsd:attribute name="accent5" type="ST_ColorSchemeIndex" use="required"/> + <xsd:attribute name="accent6" type="ST_ColorSchemeIndex" use="required"/> + <xsd:attribute name="hlink" type="ST_ColorSchemeIndex" use="required"/> + <xsd:attribute name="folHlink" type="ST_ColorSchemeIndex" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_ColorMappingOverride"> + <xsd:sequence> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="masterClrMapping" type="CT_EmptyElement"/> + <xsd:element name="overrideClrMapping" type="CT_ColorMapping"/> + </xsd:choice> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ColorSchemeAndMapping"> + <xsd:sequence> + <xsd:element name="clrScheme" type="CT_ColorScheme" minOccurs="1" maxOccurs="1"/> + <xsd:element name="clrMap" type="CT_ColorMapping" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ColorSchemeList"> + <xsd:sequence> + <xsd:element name="extraClrScheme" type="CT_ColorSchemeAndMapping" minOccurs="0" + maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_OfficeStyleSheet"> + <xsd:sequence> + <xsd:element name="themeElements" type="CT_BaseStyles" minOccurs="1" maxOccurs="1"/> + <xsd:element name="objectDefaults" type="CT_ObjectStyleDefaults" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extraClrSchemeLst" type="CT_ColorSchemeList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="custClrLst" type="CT_CustomColorList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="optional" default=""/> + </xsd:complexType> + <xsd:complexType name="CT_BaseStylesOverride"> + <xsd:sequence> + <xsd:element name="clrScheme" type="CT_ColorScheme" minOccurs="0" maxOccurs="1"/> + <xsd:element name="fontScheme" type="CT_FontScheme" minOccurs="0" maxOccurs="1"/> + <xsd:element name="fmtScheme" type="CT_StyleMatrix" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ClipboardStyleSheet"> + <xsd:sequence> + <xsd:element name="themeElements" type="CT_BaseStyles" minOccurs="1" maxOccurs="1"/> + <xsd:element name="clrMap" type="CT_ColorMapping" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="theme" type="CT_OfficeStyleSheet"/> + <xsd:element name="themeOverride" type="CT_BaseStylesOverride"/> + <xsd:element name="themeManager" type="CT_EmptyElement"/> + <xsd:complexType name="CT_TableCellProperties"> + <xsd:sequence> + <xsd:element name="lnL" type="CT_LineProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lnR" type="CT_LineProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lnT" type="CT_LineProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lnB" type="CT_LineProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lnTlToBr" type="CT_LineProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lnBlToTr" type="CT_LineProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cell3D" type="CT_Cell3D" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_FillProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="headers" type="CT_Headers" minOccurs="0"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="marL" type="ST_Coordinate32" use="optional" default="91440"/> + <xsd:attribute name="marR" type="ST_Coordinate32" use="optional" default="91440"/> + <xsd:attribute name="marT" type="ST_Coordinate32" use="optional" default="45720"/> + <xsd:attribute name="marB" type="ST_Coordinate32" use="optional" default="45720"/> + <xsd:attribute name="vert" type="ST_TextVerticalType" use="optional" default="horz"/> + <xsd:attribute name="anchor" type="ST_TextAnchoringType" use="optional" default="t"/> + <xsd:attribute name="anchorCtr" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="horzOverflow" type="ST_TextHorzOverflowType" use="optional" default="clip" + /> + </xsd:complexType> + <xsd:complexType name="CT_Headers"> + <xsd:sequence minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="header" type="xsd:string"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TableCol"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="w" type="ST_Coordinate" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TableGrid"> + <xsd:sequence> + <xsd:element name="gridCol" type="CT_TableCol" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TableCell"> + <xsd:sequence> + <xsd:element name="txBody" type="CT_TextBody" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tcPr" type="CT_TableCellProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="rowSpan" type="xsd:int" use="optional" default="1"/> + <xsd:attribute name="gridSpan" type="xsd:int" use="optional" default="1"/> + <xsd:attribute name="hMerge" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="vMerge" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="id" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TableRow"> + <xsd:sequence> + <xsd:element name="tc" type="CT_TableCell" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="h" type="ST_Coordinate" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TableProperties"> + <xsd:sequence> + <xsd:group ref="EG_FillProperties" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_EffectProperties" minOccurs="0" maxOccurs="1"/> + <xsd:choice minOccurs="0" maxOccurs="1"> + <xsd:element name="tableStyle" type="CT_TableStyle"/> + <xsd:element name="tableStyleId" type="s:ST_Guid"/> + </xsd:choice> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="rtl" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="firstRow" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="firstCol" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="lastRow" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="lastCol" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="bandRow" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="bandCol" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_Table"> + <xsd:sequence> + <xsd:element name="tblPr" type="CT_TableProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblGrid" type="CT_TableGrid" minOccurs="1" maxOccurs="1"/> + <xsd:element name="tr" type="CT_TableRow" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="tbl" type="CT_Table"/> + <xsd:complexType name="CT_Cell3D"> + <xsd:sequence> + <xsd:element name="bevel" type="CT_Bevel" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lightRig" type="CT_LightRig" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="prstMaterial" type="ST_PresetMaterialType" use="optional" default="plastic" + /> + </xsd:complexType> + <xsd:group name="EG_ThemeableFillStyle"> + <xsd:choice> + <xsd:element name="fill" type="CT_FillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="fillRef" type="CT_StyleMatrixReference" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_ThemeableLineStyle"> + <xsd:choice> + <xsd:element name="ln" type="CT_LineProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lnRef" type="CT_StyleMatrixReference" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:complexType> + <xsd:group name="EG_ThemeableEffectStyle"> + <xsd:choice> + <xsd:element name="effect" type="CT_EffectProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="effectRef" type="CT_StyleMatrixReference" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:group name="EG_ThemeableFontStyles"> + <xsd:choice> + <xsd:element name="font" type="CT_FontCollection" minOccurs="1" maxOccurs="1"/> + <xsd:element name="fontRef" type="CT_FontReference" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:simpleType name="ST_OnOffStyleType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="on"/> + <xsd:enumeration value="off"/> + <xsd:enumeration value="def"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TableStyleTextStyle"> + <xsd:sequence> + <xsd:group ref="EG_ThemeableFontStyles" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_ColorChoice" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="b" type="ST_OnOffStyleType" use="optional" default="def"/> + <xsd:attribute name="i" type="ST_OnOffStyleType" use="optional" default="def"/> + </xsd:complexType> + <xsd:complexType name="CT_TableCellBorderStyle"> + <xsd:sequence> + <xsd:element name="left" type="CT_ThemeableLineStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="right" type="CT_ThemeableLineStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="top" type="CT_ThemeableLineStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bottom" type="CT_ThemeableLineStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="insideH" type="CT_ThemeableLineStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="insideV" type="CT_ThemeableLineStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tl2br" type="CT_ThemeableLineStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tr2bl" type="CT_ThemeableLineStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TableBackgroundStyle"> + <xsd:sequence> + <xsd:group ref="EG_ThemeableFillStyle" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_ThemeableEffectStyle" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TableStyleCellStyle"> + <xsd:sequence> + <xsd:element name="tcBdr" type="CT_TableCellBorderStyle" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_ThemeableFillStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cell3D" type="CT_Cell3D" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TablePartStyle"> + <xsd:sequence> + <xsd:element name="tcTxStyle" type="CT_TableStyleTextStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tcStyle" type="CT_TableStyleCellStyle" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TableStyle"> + <xsd:sequence> + <xsd:element name="tblBg" type="CT_TableBackgroundStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="wholeTbl" type="CT_TablePartStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="band1H" type="CT_TablePartStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="band2H" type="CT_TablePartStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="band1V" type="CT_TablePartStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="band2V" type="CT_TablePartStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lastCol" type="CT_TablePartStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="firstCol" type="CT_TablePartStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lastRow" type="CT_TablePartStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="seCell" type="CT_TablePartStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="swCell" type="CT_TablePartStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="firstRow" type="CT_TablePartStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="neCell" type="CT_TablePartStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="nwCell" type="CT_TablePartStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="styleId" type="s:ST_Guid" use="required"/> + <xsd:attribute name="styleName" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TableStyleList"> + <xsd:sequence> + <xsd:element name="tblStyle" type="CT_TableStyle" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="def" type="s:ST_Guid" use="required"/> + </xsd:complexType> + <xsd:element name="tblStyleLst" type="CT_TableStyleList"/> + <xsd:complexType name="CT_TextParagraph"> + <xsd:sequence> + <xsd:element name="pPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_TextRun" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="endParaRPr" type="CT_TextCharacterProperties" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_TextAnchoringType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="t"/> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="b"/> + <xsd:enumeration value="just"/> + <xsd:enumeration value="dist"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextVertOverflowType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="overflow"/> + <xsd:enumeration value="ellipsis"/> + <xsd:enumeration value="clip"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextHorzOverflowType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="overflow"/> + <xsd:enumeration value="clip"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextVerticalType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="horz"/> + <xsd:enumeration value="vert"/> + <xsd:enumeration value="vert270"/> + <xsd:enumeration value="wordArtVert"/> + <xsd:enumeration value="eaVert"/> + <xsd:enumeration value="mongolianVert"/> + <xsd:enumeration value="wordArtVertRtl"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextWrappingType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="square"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextColumnCount"> + <xsd:restriction base="xsd:int"> + <xsd:minInclusive value="1"/> + <xsd:maxInclusive value="16"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextListStyle"> + <xsd:sequence> + <xsd:element name="defPPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lvl1pPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lvl2pPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lvl3pPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lvl4pPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lvl5pPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lvl6pPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lvl7pPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lvl8pPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="lvl9pPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_TextFontScalePercentOrPercentString"> + <xsd:union memberTypes="ST_TextFontScalePercent s:ST_Percentage"/> + </xsd:simpleType> + <xsd:simpleType name="ST_TextFontScalePercent"> + <xsd:restriction base="ST_PercentageDecimal"> + <xsd:minInclusive value="1000"/> + <xsd:maxInclusive value="100000"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextNormalAutofit"> + <xsd:attribute name="fontScale" type="ST_TextFontScalePercentOrPercentString" use="optional" + default="100%"/> + <xsd:attribute name="lnSpcReduction" type="ST_TextSpacingPercentOrPercentString" use="optional" + default="0%"/> + </xsd:complexType> + <xsd:complexType name="CT_TextShapeAutofit"/> + <xsd:complexType name="CT_TextNoAutofit"/> + <xsd:group name="EG_TextAutofit"> + <xsd:choice> + <xsd:element name="noAutofit" type="CT_TextNoAutofit"/> + <xsd:element name="normAutofit" type="CT_TextNormalAutofit"/> + <xsd:element name="spAutoFit" type="CT_TextShapeAutofit"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_TextBodyProperties"> + <xsd:sequence> + <xsd:element name="prstTxWarp" type="CT_PresetTextShape" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_TextAutofit" minOccurs="0" maxOccurs="1"/> + <xsd:element name="scene3d" type="CT_Scene3D" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_Text3D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="rot" type="ST_Angle" use="optional"/> + <xsd:attribute name="spcFirstLastPara" type="xsd:boolean" use="optional"/> + <xsd:attribute name="vertOverflow" type="ST_TextVertOverflowType" use="optional"/> + <xsd:attribute name="horzOverflow" type="ST_TextHorzOverflowType" use="optional"/> + <xsd:attribute name="vert" type="ST_TextVerticalType" use="optional"/> + <xsd:attribute name="wrap" type="ST_TextWrappingType" use="optional"/> + <xsd:attribute name="lIns" type="ST_Coordinate32" use="optional"/> + <xsd:attribute name="tIns" type="ST_Coordinate32" use="optional"/> + <xsd:attribute name="rIns" type="ST_Coordinate32" use="optional"/> + <xsd:attribute name="bIns" type="ST_Coordinate32" use="optional"/> + <xsd:attribute name="numCol" type="ST_TextColumnCount" use="optional"/> + <xsd:attribute name="spcCol" type="ST_PositiveCoordinate32" use="optional"/> + <xsd:attribute name="rtlCol" type="xsd:boolean" use="optional"/> + <xsd:attribute name="fromWordArt" type="xsd:boolean" use="optional"/> + <xsd:attribute name="anchor" type="ST_TextAnchoringType" use="optional"/> + <xsd:attribute name="anchorCtr" type="xsd:boolean" use="optional"/> + <xsd:attribute name="forceAA" type="xsd:boolean" use="optional"/> + <xsd:attribute name="upright" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="compatLnSpc" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TextBody"> + <xsd:sequence> + <xsd:element name="bodyPr" type="CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lstStyle" type="CT_TextListStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="p" type="CT_TextParagraph" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_TextBulletStartAtNum"> + <xsd:restriction base="xsd:int"> + <xsd:minInclusive value="1"/> + <xsd:maxInclusive value="32767"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextAutonumberScheme"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="alphaLcParenBoth"/> + <xsd:enumeration value="alphaUcParenBoth"/> + <xsd:enumeration value="alphaLcParenR"/> + <xsd:enumeration value="alphaUcParenR"/> + <xsd:enumeration value="alphaLcPeriod"/> + <xsd:enumeration value="alphaUcPeriod"/> + <xsd:enumeration value="arabicParenBoth"/> + <xsd:enumeration value="arabicParenR"/> + <xsd:enumeration value="arabicPeriod"/> + <xsd:enumeration value="arabicPlain"/> + <xsd:enumeration value="romanLcParenBoth"/> + <xsd:enumeration value="romanUcParenBoth"/> + <xsd:enumeration value="romanLcParenR"/> + <xsd:enumeration value="romanUcParenR"/> + <xsd:enumeration value="romanLcPeriod"/> + <xsd:enumeration value="romanUcPeriod"/> + <xsd:enumeration value="circleNumDbPlain"/> + <xsd:enumeration value="circleNumWdBlackPlain"/> + <xsd:enumeration value="circleNumWdWhitePlain"/> + <xsd:enumeration value="arabicDbPeriod"/> + <xsd:enumeration value="arabicDbPlain"/> + <xsd:enumeration value="ea1ChsPeriod"/> + <xsd:enumeration value="ea1ChsPlain"/> + <xsd:enumeration value="ea1ChtPeriod"/> + <xsd:enumeration value="ea1ChtPlain"/> + <xsd:enumeration value="ea1JpnChsDbPeriod"/> + <xsd:enumeration value="ea1JpnKorPlain"/> + <xsd:enumeration value="ea1JpnKorPeriod"/> + <xsd:enumeration value="arabic1Minus"/> + <xsd:enumeration value="arabic2Minus"/> + <xsd:enumeration value="hebrew2Minus"/> + <xsd:enumeration value="thaiAlphaPeriod"/> + <xsd:enumeration value="thaiAlphaParenR"/> + <xsd:enumeration value="thaiAlphaParenBoth"/> + <xsd:enumeration value="thaiNumPeriod"/> + <xsd:enumeration value="thaiNumParenR"/> + <xsd:enumeration value="thaiNumParenBoth"/> + <xsd:enumeration value="hindiAlphaPeriod"/> + <xsd:enumeration value="hindiNumPeriod"/> + <xsd:enumeration value="hindiNumParenR"/> + <xsd:enumeration value="hindiAlpha1Period"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextBulletColorFollowText"/> + <xsd:group name="EG_TextBulletColor"> + <xsd:choice> + <xsd:element name="buClrTx" type="CT_TextBulletColorFollowText" minOccurs="1" maxOccurs="1"/> + <xsd:element name="buClr" type="CT_Color" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:simpleType name="ST_TextBulletSize"> + <xsd:union memberTypes="ST_TextBulletSizePercent ST_TextBulletSizeDecimal"/> + </xsd:simpleType> + <xsd:simpleType name="ST_TextBulletSizePercent"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="0*((2[5-9])|([3-9][0-9])|([1-3][0-9][0-9])|400)%"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextBulletSizeDecimal"> + <xsd:restriction base="ST_PercentageDecimal"> + <xsd:minInclusive value="25000"/> + <xsd:maxInclusive value="400000"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextBulletSizeFollowText"/> + <xsd:complexType name="CT_TextBulletSizePercent"> + <xsd:attribute name="val" type="ST_TextBulletSizePercent" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TextBulletSizePoint"> + <xsd:attribute name="val" type="ST_TextFontSize" use="required"/> + </xsd:complexType> + <xsd:group name="EG_TextBulletSize"> + <xsd:choice> + <xsd:element name="buSzTx" type="CT_TextBulletSizeFollowText"/> + <xsd:element name="buSzPct" type="CT_TextBulletSizePercent"/> + <xsd:element name="buSzPts" type="CT_TextBulletSizePoint"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_TextBulletTypefaceFollowText"/> + <xsd:group name="EG_TextBulletTypeface"> + <xsd:choice> + <xsd:element name="buFontTx" type="CT_TextBulletTypefaceFollowText"/> + <xsd:element name="buFont" type="CT_TextFont"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_TextAutonumberBullet"> + <xsd:attribute name="type" type="ST_TextAutonumberScheme" use="required"/> + <xsd:attribute name="startAt" type="ST_TextBulletStartAtNum" use="optional" default="1"/> + </xsd:complexType> + <xsd:complexType name="CT_TextCharBullet"> + <xsd:attribute name="char" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TextBlipBullet"> + <xsd:sequence> + <xsd:element name="blip" type="CT_Blip" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TextNoBullet"/> + <xsd:group name="EG_TextBullet"> + <xsd:choice> + <xsd:element name="buNone" type="CT_TextNoBullet"/> + <xsd:element name="buAutoNum" type="CT_TextAutonumberBullet"/> + <xsd:element name="buChar" type="CT_TextCharBullet"/> + <xsd:element name="buBlip" type="CT_TextBlipBullet"/> + </xsd:choice> + </xsd:group> + <xsd:simpleType name="ST_TextPoint"> + <xsd:union memberTypes="ST_TextPointUnqualified s:ST_UniversalMeasure"/> + </xsd:simpleType> + <xsd:simpleType name="ST_TextPointUnqualified"> + <xsd:restriction base="xsd:int"> + <xsd:minInclusive value="-400000"/> + <xsd:maxInclusive value="400000"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextNonNegativePoint"> + <xsd:restriction base="xsd:int"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="400000"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextFontSize"> + <xsd:restriction base="xsd:int"> + <xsd:minInclusive value="100"/> + <xsd:maxInclusive value="400000"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextTypeface"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="ST_PitchFamily"> + <xsd:restriction base="xsd:byte"> + <xsd:enumeration value="00"/> + <xsd:enumeration value="01"/> + <xsd:enumeration value="02"/> + <xsd:enumeration value="16"/> + <xsd:enumeration value="17"/> + <xsd:enumeration value="18"/> + <xsd:enumeration value="32"/> + <xsd:enumeration value="33"/> + <xsd:enumeration value="34"/> + <xsd:enumeration value="48"/> + <xsd:enumeration value="49"/> + <xsd:enumeration value="50"/> + <xsd:enumeration value="64"/> + <xsd:enumeration value="65"/> + <xsd:enumeration value="66"/> + <xsd:enumeration value="80"/> + <xsd:enumeration value="81"/> + <xsd:enumeration value="82"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextFont"> + <xsd:attribute name="typeface" type="ST_TextTypeface" use="required"/> + <xsd:attribute name="panose" type="s:ST_Panose" use="optional"/> + <xsd:attribute name="pitchFamily" type="ST_PitchFamily" use="optional" default="0"/> + <xsd:attribute name="charset" type="xsd:byte" use="optional" default="1"/> + </xsd:complexType> + <xsd:simpleType name="ST_TextUnderlineType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="words"/> + <xsd:enumeration value="sng"/> + <xsd:enumeration value="dbl"/> + <xsd:enumeration value="heavy"/> + <xsd:enumeration value="dotted"/> + <xsd:enumeration value="dottedHeavy"/> + <xsd:enumeration value="dash"/> + <xsd:enumeration value="dashHeavy"/> + <xsd:enumeration value="dashLong"/> + <xsd:enumeration value="dashLongHeavy"/> + <xsd:enumeration value="dotDash"/> + <xsd:enumeration value="dotDashHeavy"/> + <xsd:enumeration value="dotDotDash"/> + <xsd:enumeration value="dotDotDashHeavy"/> + <xsd:enumeration value="wavy"/> + <xsd:enumeration value="wavyHeavy"/> + <xsd:enumeration value="wavyDbl"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextUnderlineLineFollowText"/> + <xsd:complexType name="CT_TextUnderlineFillFollowText"/> + <xsd:complexType name="CT_TextUnderlineFillGroupWrapper"> + <xsd:group ref="EG_FillProperties" minOccurs="1" maxOccurs="1"/> + </xsd:complexType> + <xsd:group name="EG_TextUnderlineLine"> + <xsd:choice> + <xsd:element name="uLnTx" type="CT_TextUnderlineLineFollowText"/> + <xsd:element name="uLn" type="CT_LineProperties" minOccurs="0" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:group name="EG_TextUnderlineFill"> + <xsd:choice> + <xsd:element name="uFillTx" type="CT_TextUnderlineFillFollowText"/> + <xsd:element name="uFill" type="CT_TextUnderlineFillGroupWrapper"/> + </xsd:choice> + </xsd:group> + <xsd:simpleType name="ST_TextStrikeType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="noStrike"/> + <xsd:enumeration value="sngStrike"/> + <xsd:enumeration value="dblStrike"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextCapsType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="small"/> + <xsd:enumeration value="all"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextCharacterProperties"> + <xsd:sequence> + <xsd:element name="ln" type="CT_LineProperties" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_FillProperties" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_EffectProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="highlight" type="CT_Color" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_TextUnderlineLine" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_TextUnderlineFill" minOccurs="0" maxOccurs="1"/> + <xsd:element name="latin" type="CT_TextFont" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ea" type="CT_TextFont" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cs" type="CT_TextFont" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sym" type="CT_TextFont" minOccurs="0" maxOccurs="1"/> + <xsd:element name="hlinkClick" type="CT_Hyperlink" minOccurs="0" maxOccurs="1"/> + <xsd:element name="hlinkMouseOver" type="CT_Hyperlink" minOccurs="0" maxOccurs="1"/> + <xsd:element name="rtl" type="CT_Boolean" minOccurs="0"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="kumimoji" type="xsd:boolean" use="optional"/> + <xsd:attribute name="lang" type="s:ST_Lang" use="optional"/> + <xsd:attribute name="altLang" type="s:ST_Lang" use="optional"/> + <xsd:attribute name="sz" type="ST_TextFontSize" use="optional"/> + <xsd:attribute name="b" type="xsd:boolean" use="optional"/> + <xsd:attribute name="i" type="xsd:boolean" use="optional"/> + <xsd:attribute name="u" type="ST_TextUnderlineType" use="optional"/> + <xsd:attribute name="strike" type="ST_TextStrikeType" use="optional"/> + <xsd:attribute name="kern" type="ST_TextNonNegativePoint" use="optional"/> + <xsd:attribute name="cap" type="ST_TextCapsType" use="optional" default="none"/> + <xsd:attribute name="spc" type="ST_TextPoint" use="optional"/> + <xsd:attribute name="normalizeH" type="xsd:boolean" use="optional"/> + <xsd:attribute name="baseline" type="ST_Percentage" use="optional"/> + <xsd:attribute name="noProof" type="xsd:boolean" use="optional"/> + <xsd:attribute name="dirty" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="err" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="smtClean" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="smtId" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="bmk" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Boolean"> + <xsd:attribute name="val" type="s:ST_OnOff" default="0"/> + </xsd:complexType> + <xsd:simpleType name="ST_TextSpacingPoint"> + <xsd:restriction base="xsd:int"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="158400"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextSpacingPercentOrPercentString"> + <xsd:union memberTypes="ST_TextSpacingPercent s:ST_Percentage"/> + </xsd:simpleType> + <xsd:simpleType name="ST_TextSpacingPercent"> + <xsd:restriction base="ST_PercentageDecimal"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="13200000"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextSpacingPercent"> + <xsd:attribute name="val" type="ST_TextSpacingPercentOrPercentString" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TextSpacingPoint"> + <xsd:attribute name="val" type="ST_TextSpacingPoint" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_TextMargin"> + <xsd:restriction base="ST_Coordinate32Unqualified"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="51206400"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextIndent"> + <xsd:restriction base="ST_Coordinate32Unqualified"> + <xsd:minInclusive value="-51206400"/> + <xsd:maxInclusive value="51206400"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextTabAlignType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="l"/> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="r"/> + <xsd:enumeration value="dec"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextTabStop"> + <xsd:attribute name="pos" type="ST_Coordinate32" use="optional"/> + <xsd:attribute name="algn" type="ST_TextTabAlignType" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TextTabStopList"> + <xsd:sequence> + <xsd:element name="tab" type="CT_TextTabStop" minOccurs="0" maxOccurs="32"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TextLineBreak"> + <xsd:sequence> + <xsd:element name="rPr" type="CT_TextCharacterProperties" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TextSpacing"> + <xsd:choice> + <xsd:element name="spcPct" type="CT_TextSpacingPercent"/> + <xsd:element name="spcPts" type="CT_TextSpacingPoint"/> + </xsd:choice> + </xsd:complexType> + <xsd:simpleType name="ST_TextAlignType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="l"/> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="r"/> + <xsd:enumeration value="just"/> + <xsd:enumeration value="justLow"/> + <xsd:enumeration value="dist"/> + <xsd:enumeration value="thaiDist"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextFontAlignType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="auto"/> + <xsd:enumeration value="t"/> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="base"/> + <xsd:enumeration value="b"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextIndentLevelType"> + <xsd:restriction base="xsd:int"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="8"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextParagraphProperties"> + <xsd:sequence> + <xsd:element name="lnSpc" type="CT_TextSpacing" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spcBef" type="CT_TextSpacing" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spcAft" type="CT_TextSpacing" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_TextBulletColor" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_TextBulletSize" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_TextBulletTypeface" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_TextBullet" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tabLst" type="CT_TextTabStopList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="defRPr" type="CT_TextCharacterProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="marL" type="ST_TextMargin" use="optional"/> + <xsd:attribute name="marR" type="ST_TextMargin" use="optional"/> + <xsd:attribute name="lvl" type="ST_TextIndentLevelType" use="optional"/> + <xsd:attribute name="indent" type="ST_TextIndent" use="optional"/> + <xsd:attribute name="algn" type="ST_TextAlignType" use="optional"/> + <xsd:attribute name="defTabSz" type="ST_Coordinate32" use="optional"/> + <xsd:attribute name="rtl" type="xsd:boolean" use="optional"/> + <xsd:attribute name="eaLnBrk" type="xsd:boolean" use="optional"/> + <xsd:attribute name="fontAlgn" type="ST_TextFontAlignType" use="optional"/> + <xsd:attribute name="latinLnBrk" type="xsd:boolean" use="optional"/> + <xsd:attribute name="hangingPunct" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TextField"> + <xsd:sequence> + <xsd:element name="rPr" type="CT_TextCharacterProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="t" type="xsd:string" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="id" type="s:ST_Guid" use="required"/> + <xsd:attribute name="type" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:group name="EG_TextRun"> + <xsd:choice> + <xsd:element name="r" type="CT_RegularTextRun"/> + <xsd:element name="br" type="CT_TextLineBreak"/> + <xsd:element name="fld" type="CT_TextField"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_RegularTextRun"> + <xsd:sequence> + <xsd:element name="rPr" type="CT_TextCharacterProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="t" type="xsd:string" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd new file mode 100644 index 0000000..1dbf051 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/drawingml/2006/picture" + xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" elementFormDefault="qualified" + targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/picture"> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main" + schemaLocation="dml-main.xsd"/> + <xsd:complexType name="CT_PictureNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvPicPr" type="a:CT_NonVisualPictureProperties" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Picture"> + <xsd:sequence minOccurs="1" maxOccurs="1"> + <xsd:element name="nvPicPr" type="CT_PictureNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="blipFill" type="a:CT_BlipFillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="pic" type="CT_Picture"/> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd new file mode 100644 index 0000000..f1af17d --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd @@ -0,0 +1,185 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" + xmlns="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" + xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" + elementFormDefault="qualified"> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main" + schemaLocation="dml-main.xsd"/> + <xsd:import schemaLocation="shared-relationshipReference.xsd" + namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"/> + <xsd:element name="from" type="CT_Marker"/> + <xsd:element name="to" type="CT_Marker"/> + <xsd:complexType name="CT_AnchorClientData"> + <xsd:attribute name="fLocksWithSheet" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="fPrintsWithSheet" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_ShapeNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvSpPr" type="a:CT_NonVisualDrawingShapeProps" minOccurs="1" maxOccurs="1" + /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Shape"> + <xsd:sequence> + <xsd:element name="nvSpPr" type="CT_ShapeNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txBody" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="macro" type="xsd:string" use="optional"/> + <xsd:attribute name="textlink" type="xsd:string" use="optional"/> + <xsd:attribute name="fLocksText" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_ConnectorNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvCxnSpPr" type="a:CT_NonVisualConnectorProperties" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Connector"> + <xsd:sequence> + <xsd:element name="nvCxnSpPr" type="CT_ConnectorNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="macro" type="xsd:string" use="optional"/> + <xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_PictureNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvPicPr" type="a:CT_NonVisualPictureProperties" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Picture"> + <xsd:sequence> + <xsd:element name="nvPicPr" type="CT_PictureNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="blipFill" type="a:CT_BlipFillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="macro" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_GraphicalObjectFrameNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties" + minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GraphicalObjectFrame"> + <xsd:sequence> + <xsd:element name="nvGraphicFramePr" type="CT_GraphicalObjectFrameNonVisual" minOccurs="1" + maxOccurs="1"/> + <xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="1" maxOccurs="1"/> + <xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="macro" type="xsd:string" use="optional"/> + <xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_GroupShapeNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvGrpSpPr" type="a:CT_NonVisualGroupDrawingShapeProps" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GroupShape"> + <xsd:sequence> + <xsd:element name="nvGrpSpPr" type="CT_GroupShapeNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="grpSpPr" type="a:CT_GroupShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="sp" type="CT_Shape"/> + <xsd:element name="grpSp" type="CT_GroupShape"/> + <xsd:element name="graphicFrame" type="CT_GraphicalObjectFrame"/> + <xsd:element name="cxnSp" type="CT_Connector"/> + <xsd:element name="pic" type="CT_Picture"/> + </xsd:choice> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_ObjectChoices"> + <xsd:sequence> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="sp" type="CT_Shape"/> + <xsd:element name="grpSp" type="CT_GroupShape"/> + <xsd:element name="graphicFrame" type="CT_GraphicalObjectFrame"/> + <xsd:element name="cxnSp" type="CT_Connector"/> + <xsd:element name="pic" type="CT_Picture"/> + <xsd:element name="contentPart" type="CT_Rel"/> + </xsd:choice> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_Rel"> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_ColID"> + <xsd:restriction base="xsd:int"> + <xsd:minInclusive value="0"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_RowID"> + <xsd:restriction base="xsd:int"> + <xsd:minInclusive value="0"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Marker"> + <xsd:sequence> + <xsd:element name="col" type="ST_ColID"/> + <xsd:element name="colOff" type="a:ST_Coordinate"/> + <xsd:element name="row" type="ST_RowID"/> + <xsd:element name="rowOff" type="a:ST_Coordinate"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_EditAs"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="twoCell"/> + <xsd:enumeration value="oneCell"/> + <xsd:enumeration value="absolute"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TwoCellAnchor"> + <xsd:sequence> + <xsd:element name="from" type="CT_Marker"/> + <xsd:element name="to" type="CT_Marker"/> + <xsd:group ref="EG_ObjectChoices"/> + <xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="editAs" type="ST_EditAs" use="optional" default="twoCell"/> + </xsd:complexType> + <xsd:complexType name="CT_OneCellAnchor"> + <xsd:sequence> + <xsd:element name="from" type="CT_Marker"/> + <xsd:element name="ext" type="a:CT_PositiveSize2D"/> + <xsd:group ref="EG_ObjectChoices"/> + <xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_AbsoluteAnchor"> + <xsd:sequence> + <xsd:element name="pos" type="a:CT_Point2D"/> + <xsd:element name="ext" type="a:CT_PositiveSize2D"/> + <xsd:group ref="EG_ObjectChoices"/> + <xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_Anchor"> + <xsd:choice> + <xsd:element name="twoCellAnchor" type="CT_TwoCellAnchor"/> + <xsd:element name="oneCellAnchor" type="CT_OneCellAnchor"/> + <xsd:element name="absoluteAnchor" type="CT_AbsoluteAnchor"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_Drawing"> + <xsd:sequence> + <xsd:group ref="EG_Anchor" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="wsDr" type="CT_Drawing"/> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd new file mode 100644 index 0000000..0a185ab --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd @@ -0,0 +1,287 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" + xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" + xmlns:dpct="http://schemas.openxmlformats.org/drawingml/2006/picture" + xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + xmlns="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" + targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" + elementFormDefault="qualified"> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main" + schemaLocation="dml-main.xsd"/> + <xsd:import schemaLocation="wml.xsd" + namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main"/> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/picture" + schemaLocation="dml-picture.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + schemaLocation="shared-relationshipReference.xsd"/> + <xsd:complexType name="CT_EffectExtent"> + <xsd:attribute name="l" type="a:ST_Coordinate" use="required"/> + <xsd:attribute name="t" type="a:ST_Coordinate" use="required"/> + <xsd:attribute name="r" type="a:ST_Coordinate" use="required"/> + <xsd:attribute name="b" type="a:ST_Coordinate" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_WrapDistance"> + <xsd:restriction base="xsd:unsignedInt"/> + </xsd:simpleType> + <xsd:complexType name="CT_Inline"> + <xsd:sequence> + <xsd:element name="extent" type="a:CT_PositiveSize2D"/> + <xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/> + <xsd:element name="docPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties" + minOccurs="0" maxOccurs="1"/> + <xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/> + <xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/> + <xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/> + <xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_WrapText"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="bothSides"/> + <xsd:enumeration value="left"/> + <xsd:enumeration value="right"/> + <xsd:enumeration value="largest"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_WrapPath"> + <xsd:sequence> + <xsd:element name="start" type="a:CT_Point2D" minOccurs="1" maxOccurs="1"/> + <xsd:element name="lineTo" type="a:CT_Point2D" minOccurs="2" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="edited" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_WrapNone"/> + <xsd:complexType name="CT_WrapSquare"> + <xsd:sequence> + <xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="wrapText" type="ST_WrapText" use="required"/> + <xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/> + <xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/> + <xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/> + <xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_WrapTight"> + <xsd:sequence> + <xsd:element name="wrapPolygon" type="CT_WrapPath" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="wrapText" type="ST_WrapText" use="required"/> + <xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/> + <xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_WrapThrough"> + <xsd:sequence> + <xsd:element name="wrapPolygon" type="CT_WrapPath" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="wrapText" type="ST_WrapText" use="required"/> + <xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/> + <xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_WrapTopBottom"> + <xsd:sequence> + <xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/> + <xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/> + </xsd:complexType> + <xsd:group name="EG_WrapType"> + <xsd:sequence> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="wrapNone" type="CT_WrapNone" minOccurs="1" maxOccurs="1"/> + <xsd:element name="wrapSquare" type="CT_WrapSquare" minOccurs="1" maxOccurs="1"/> + <xsd:element name="wrapTight" type="CT_WrapTight" minOccurs="1" maxOccurs="1"/> + <xsd:element name="wrapThrough" type="CT_WrapThrough" minOccurs="1" maxOccurs="1"/> + <xsd:element name="wrapTopAndBottom" type="CT_WrapTopBottom" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:sequence> + </xsd:group> + <xsd:simpleType name="ST_PositionOffset"> + <xsd:restriction base="xsd:int"/> + </xsd:simpleType> + <xsd:simpleType name="ST_AlignH"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="left"/> + <xsd:enumeration value="right"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="inside"/> + <xsd:enumeration value="outside"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_RelFromH"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="margin"/> + <xsd:enumeration value="page"/> + <xsd:enumeration value="column"/> + <xsd:enumeration value="character"/> + <xsd:enumeration value="leftMargin"/> + <xsd:enumeration value="rightMargin"/> + <xsd:enumeration value="insideMargin"/> + <xsd:enumeration value="outsideMargin"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PosH"> + <xsd:sequence> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="align" type="ST_AlignH" minOccurs="1" maxOccurs="1"/> + <xsd:element name="posOffset" type="ST_PositionOffset" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:sequence> + <xsd:attribute name="relativeFrom" type="ST_RelFromH" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_AlignV"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="top"/> + <xsd:enumeration value="bottom"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="inside"/> + <xsd:enumeration value="outside"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_RelFromV"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="margin"/> + <xsd:enumeration value="page"/> + <xsd:enumeration value="paragraph"/> + <xsd:enumeration value="line"/> + <xsd:enumeration value="topMargin"/> + <xsd:enumeration value="bottomMargin"/> + <xsd:enumeration value="insideMargin"/> + <xsd:enumeration value="outsideMargin"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PosV"> + <xsd:sequence> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="align" type="ST_AlignV" minOccurs="1" maxOccurs="1"/> + <xsd:element name="posOffset" type="ST_PositionOffset" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + </xsd:sequence> + <xsd:attribute name="relativeFrom" type="ST_RelFromV" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Anchor"> + <xsd:sequence> + <xsd:element name="simplePos" type="a:CT_Point2D"/> + <xsd:element name="positionH" type="CT_PosH"/> + <xsd:element name="positionV" type="CT_PosV"/> + <xsd:element name="extent" type="a:CT_PositiveSize2D"/> + <xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/> + <xsd:group ref="EG_WrapType"/> + <xsd:element name="docPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties" + minOccurs="0" maxOccurs="1"/> + <xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/> + <xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/> + <xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/> + <xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/> + <xsd:attribute name="simplePos" type="xsd:boolean"/> + <xsd:attribute name="relativeHeight" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="behindDoc" type="xsd:boolean" use="required"/> + <xsd:attribute name="locked" type="xsd:boolean" use="required"/> + <xsd:attribute name="layoutInCell" type="xsd:boolean" use="required"/> + <xsd:attribute name="hidden" type="xsd:boolean" use="optional"/> + <xsd:attribute name="allowOverlap" type="xsd:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TxbxContent"> + <xsd:group ref="w:EG_BlockLevelElts" minOccurs="1" maxOccurs="unbounded"/> + </xsd:complexType> + <xsd:complexType name="CT_TextboxInfo"> + <xsd:sequence> + <xsd:element name="txbxContent" type="CT_TxbxContent" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:unsignedShort" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_LinkedTextboxInformation"> + <xsd:sequence> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:unsignedShort" use="required"/> + <xsd:attribute name="seq" type="xsd:unsignedShort" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_WordprocessingShape"> + <xsd:sequence minOccurs="1" maxOccurs="1"> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="cNvSpPr" type="a:CT_NonVisualDrawingShapeProps" minOccurs="1" + maxOccurs="1"/> + <xsd:element name="cNvCnPr" type="a:CT_NonVisualConnectorProperties" minOccurs="1" + maxOccurs="1"/> + </xsd:choice> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + <xsd:choice minOccurs="0" maxOccurs="1"> + <xsd:element name="txbx" type="CT_TextboxInfo" minOccurs="1" maxOccurs="1"/> + <xsd:element name="linkedTxbx" type="CT_LinkedTextboxInformation" minOccurs="1" + maxOccurs="1"/> + </xsd:choice> + <xsd:element name="bodyPr" type="a:CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="normalEastAsianFlow" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_GraphicFrame"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvFrPr" type="a:CT_NonVisualGraphicFrameProperties" minOccurs="1" + maxOccurs="1"/> + <xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="1" maxOccurs="1"/> + <xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_WordprocessingContentPartNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cNvContentPartPr" type="a:CT_NonVisualContentPartProperties" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_WordprocessingContentPart"> + <xsd:sequence> + <xsd:element name="nvContentPartPr" type="CT_WordprocessingContentPartNonVisual" minOccurs="0" maxOccurs="1"/> + <xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="bwMode" type="a:ST_BlackWhiteMode" use="optional"/> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_WordprocessingGroup"> + <xsd:sequence minOccurs="1" maxOccurs="1"> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cNvGrpSpPr" type="a:CT_NonVisualGroupDrawingShapeProps" minOccurs="1" + maxOccurs="1"/> + <xsd:element name="grpSpPr" type="a:CT_GroupShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element ref="wsp"/> + <xsd:element name="grpSp" type="CT_WordprocessingGroup"/> + <xsd:element name="graphicFrame" type="CT_GraphicFrame"/> + <xsd:element ref="dpct:pic"/> + <xsd:element name="contentPart" type="CT_WordprocessingContentPart"/> + </xsd:choice> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_WordprocessingCanvas"> + <xsd:sequence minOccurs="1" maxOccurs="1"> + <xsd:element name="bg" type="a:CT_BackgroundFormatting" minOccurs="0" maxOccurs="1"/> + <xsd:element name="whole" type="a:CT_WholeE2oFormatting" minOccurs="0" maxOccurs="1"/> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element ref="wsp"/> + <xsd:element ref="dpct:pic"/> + <xsd:element name="contentPart" type="CT_WordprocessingContentPart"/> + <xsd:element ref="wgp"/> + <xsd:element name="graphicFrame" type="CT_GraphicFrame"/> + </xsd:choice> + <xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="wpc" type="CT_WordprocessingCanvas"/> + <xsd:element name="wgp" type="CT_WordprocessingGroup"/> + <xsd:element name="wsp" type="CT_WordprocessingShape"/> + <xsd:element name="inline" type="CT_Inline"/> + <xsd:element name="anchor" type="CT_Anchor"/> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd new file mode 100644 index 0000000..14ef488 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd @@ -0,0 +1,1676 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/presentationml/2006/main" + xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" + xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" + xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + elementFormDefault="qualified" + targetNamespace="http://schemas.openxmlformats.org/presentationml/2006/main"> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + schemaLocation="shared-relationshipReference.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main" + schemaLocation="dml-main.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + schemaLocation="shared-commonSimpleTypes.xsd"/> + <xsd:simpleType name="ST_TransitionSideDirectionType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="l"/> + <xsd:enumeration value="u"/> + <xsd:enumeration value="r"/> + <xsd:enumeration value="d"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TransitionCornerDirectionType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="lu"/> + <xsd:enumeration value="ru"/> + <xsd:enumeration value="ld"/> + <xsd:enumeration value="rd"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TransitionInOutDirectionType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="out"/> + <xsd:enumeration value="in"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SideDirectionTransition"> + <xsd:attribute name="dir" type="ST_TransitionSideDirectionType" use="optional" default="l"/> + </xsd:complexType> + <xsd:complexType name="CT_CornerDirectionTransition"> + <xsd:attribute name="dir" type="ST_TransitionCornerDirectionType" use="optional" default="lu"/> + </xsd:complexType> + <xsd:simpleType name="ST_TransitionEightDirectionType"> + <xsd:union memberTypes="ST_TransitionSideDirectionType ST_TransitionCornerDirectionType"/> + </xsd:simpleType> + <xsd:complexType name="CT_EightDirectionTransition"> + <xsd:attribute name="dir" type="ST_TransitionEightDirectionType" use="optional" default="l"/> + </xsd:complexType> + <xsd:complexType name="CT_OrientationTransition"> + <xsd:attribute name="dir" type="ST_Direction" use="optional" default="horz"/> + </xsd:complexType> + <xsd:complexType name="CT_InOutTransition"> + <xsd:attribute name="dir" type="ST_TransitionInOutDirectionType" use="optional" default="out"/> + </xsd:complexType> + <xsd:complexType name="CT_OptionalBlackTransition"> + <xsd:attribute name="thruBlk" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_SplitTransition"> + <xsd:attribute name="orient" type="ST_Direction" use="optional" default="horz"/> + <xsd:attribute name="dir" type="ST_TransitionInOutDirectionType" use="optional" default="out"/> + </xsd:complexType> + <xsd:complexType name="CT_WheelTransition"> + <xsd:attribute name="spokes" type="xsd:unsignedInt" use="optional" default="4"/> + </xsd:complexType> + <xsd:complexType name="CT_TransitionStartSoundAction"> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="snd" type="a:CT_EmbeddedWAVAudioFile"/> + </xsd:sequence> + <xsd:attribute name="loop" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_TransitionSoundAction"> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="stSnd" type="CT_TransitionStartSoundAction"/> + <xsd:element name="endSnd" type="CT_Empty"/> + </xsd:choice> + </xsd:complexType> + <xsd:simpleType name="ST_TransitionSpeed"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="slow"/> + <xsd:enumeration value="med"/> + <xsd:enumeration value="fast"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SlideTransition"> + <xsd:sequence> + <xsd:choice minOccurs="0" maxOccurs="1"> + <xsd:element name="blinds" type="CT_OrientationTransition"/> + <xsd:element name="checker" type="CT_OrientationTransition"/> + <xsd:element name="circle" type="CT_Empty"/> + <xsd:element name="dissolve" type="CT_Empty"/> + <xsd:element name="comb" type="CT_OrientationTransition"/> + <xsd:element name="cover" type="CT_EightDirectionTransition"/> + <xsd:element name="cut" type="CT_OptionalBlackTransition"/> + <xsd:element name="diamond" type="CT_Empty"/> + <xsd:element name="fade" type="CT_OptionalBlackTransition"/> + <xsd:element name="newsflash" type="CT_Empty"/> + <xsd:element name="plus" type="CT_Empty"/> + <xsd:element name="pull" type="CT_EightDirectionTransition"/> + <xsd:element name="push" type="CT_SideDirectionTransition"/> + <xsd:element name="random" type="CT_Empty"/> + <xsd:element name="randomBar" type="CT_OrientationTransition"/> + <xsd:element name="split" type="CT_SplitTransition"/> + <xsd:element name="strips" type="CT_CornerDirectionTransition"/> + <xsd:element name="wedge" type="CT_Empty"/> + <xsd:element name="wheel" type="CT_WheelTransition"/> + <xsd:element name="wipe" type="CT_SideDirectionTransition"/> + <xsd:element name="zoom" type="CT_InOutTransition"/> + </xsd:choice> + <xsd:element name="sndAc" minOccurs="0" maxOccurs="1" type="CT_TransitionSoundAction"/> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="spd" type="ST_TransitionSpeed" use="optional" default="fast"/> + <xsd:attribute name="advClick" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="advTm" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_TLTimeIndefinite"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="indefinite"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TLTime"> + <xsd:union memberTypes="xsd:unsignedInt ST_TLTimeIndefinite"/> + </xsd:simpleType> + <xsd:simpleType name="ST_TLTimeNodeID"> + <xsd:restriction base="xsd:unsignedInt"/> + </xsd:simpleType> + <xsd:complexType name="CT_TLIterateIntervalTime"> + <xsd:attribute name="val" type="ST_TLTime" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TLIterateIntervalPercentage"> + <xsd:attribute name="val" type="a:ST_PositivePercentage" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_IterateType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="el"/> + <xsd:enumeration value="wd"/> + <xsd:enumeration value="lt"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLIterateData"> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="tmAbs" type="CT_TLIterateIntervalTime"/> + <xsd:element name="tmPct" type="CT_TLIterateIntervalPercentage"/> + </xsd:choice> + <xsd:attribute name="type" type="ST_IterateType" use="optional" default="el"/> + <xsd:attribute name="backwards" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_TLSubShapeId"> + <xsd:attribute name="spid" type="a:ST_ShapeID" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TLTextTargetElement"> + <xsd:choice minOccurs="0" maxOccurs="1"> + <xsd:element name="charRg" type="CT_IndexRange"/> + <xsd:element name="pRg" type="CT_IndexRange"/> + </xsd:choice> + </xsd:complexType> + <xsd:simpleType name="ST_TLChartSubelementType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="gridLegend"/> + <xsd:enumeration value="series"/> + <xsd:enumeration value="category"/> + <xsd:enumeration value="ptInSeries"/> + <xsd:enumeration value="ptInCategory"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLOleChartTargetElement"> + <xsd:attribute name="type" type="ST_TLChartSubelementType" use="required"/> + <xsd:attribute name="lvl" type="xsd:unsignedInt" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_TLShapeTargetElement"> + <xsd:choice minOccurs="0" maxOccurs="1"> + <xsd:element name="bg" type="CT_Empty"/> + <xsd:element name="subSp" type="CT_TLSubShapeId"/> + <xsd:element name="oleChartEl" type="CT_TLOleChartTargetElement"/> + <xsd:element name="txEl" type="CT_TLTextTargetElement"/> + <xsd:element name="graphicEl" type="a:CT_AnimationElementChoice"/> + </xsd:choice> + <xsd:attribute name="spid" type="a:ST_DrawingElementId" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TLTimeTargetElement"> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="sldTgt" type="CT_Empty"/> + <xsd:element name="sndTgt" type="a:CT_EmbeddedWAVAudioFile"/> + <xsd:element name="spTgt" type="CT_TLShapeTargetElement"/> + <xsd:element name="inkTgt" type="CT_TLSubShapeId"/> + </xsd:choice> + </xsd:complexType> + <xsd:complexType name="CT_TLTriggerTimeNodeID"> + <xsd:attribute name="val" type="ST_TLTimeNodeID" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_TLTriggerRuntimeNode"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="first"/> + <xsd:enumeration value="last"/> + <xsd:enumeration value="all"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLTriggerRuntimeNode"> + <xsd:attribute name="val" type="ST_TLTriggerRuntimeNode" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_TLTriggerEvent"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="onBegin"/> + <xsd:enumeration value="onEnd"/> + <xsd:enumeration value="begin"/> + <xsd:enumeration value="end"/> + <xsd:enumeration value="onClick"/> + <xsd:enumeration value="onDblClick"/> + <xsd:enumeration value="onMouseOver"/> + <xsd:enumeration value="onMouseOut"/> + <xsd:enumeration value="onNext"/> + <xsd:enumeration value="onPrev"/> + <xsd:enumeration value="onStopAudio"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLTimeCondition"> + <xsd:choice minOccurs="0" maxOccurs="1"> + <xsd:element name="tgtEl" type="CT_TLTimeTargetElement"/> + <xsd:element name="tn" type="CT_TLTriggerTimeNodeID"/> + <xsd:element name="rtn" type="CT_TLTriggerRuntimeNode"/> + </xsd:choice> + <xsd:attribute name="evt" use="optional" type="ST_TLTriggerEvent"/> + <xsd:attribute name="delay" type="ST_TLTime" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TLTimeConditionList"> + <xsd:sequence> + <xsd:element name="cond" type="CT_TLTimeCondition" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TimeNodeList"> + <xsd:choice minOccurs="1" maxOccurs="unbounded"> + <xsd:element name="par" type="CT_TLTimeNodeParallel"/> + <xsd:element name="seq" type="CT_TLTimeNodeSequence"/> + <xsd:element name="excl" type="CT_TLTimeNodeExclusive"/> + <xsd:element name="anim" type="CT_TLAnimateBehavior"/> + <xsd:element name="animClr" type="CT_TLAnimateColorBehavior"/> + <xsd:element name="animEffect" type="CT_TLAnimateEffectBehavior"/> + <xsd:element name="animMotion" type="CT_TLAnimateMotionBehavior"/> + <xsd:element name="animRot" type="CT_TLAnimateRotationBehavior"/> + <xsd:element name="animScale" type="CT_TLAnimateScaleBehavior"/> + <xsd:element name="cmd" type="CT_TLCommandBehavior"/> + <xsd:element name="set" type="CT_TLSetBehavior"/> + <xsd:element name="audio" type="CT_TLMediaNodeAudio"/> + <xsd:element name="video" type="CT_TLMediaNodeVideo"/> + </xsd:choice> + </xsd:complexType> + <xsd:simpleType name="ST_TLTimeNodePresetClassType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="entr"/> + <xsd:enumeration value="exit"/> + <xsd:enumeration value="emph"/> + <xsd:enumeration value="path"/> + <xsd:enumeration value="verb"/> + <xsd:enumeration value="mediacall"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TLTimeNodeRestartType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="always"/> + <xsd:enumeration value="whenNotActive"/> + <xsd:enumeration value="never"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TLTimeNodeFillType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="remove"/> + <xsd:enumeration value="freeze"/> + <xsd:enumeration value="hold"/> + <xsd:enumeration value="transition"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TLTimeNodeSyncType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="canSlip"/> + <xsd:enumeration value="locked"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TLTimeNodeMasterRelation"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="sameClick"/> + <xsd:enumeration value="lastClick"/> + <xsd:enumeration value="nextClick"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TLTimeNodeType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="clickEffect"/> + <xsd:enumeration value="withEffect"/> + <xsd:enumeration value="afterEffect"/> + <xsd:enumeration value="mainSeq"/> + <xsd:enumeration value="interactiveSeq"/> + <xsd:enumeration value="clickPar"/> + <xsd:enumeration value="withGroup"/> + <xsd:enumeration value="afterGroup"/> + <xsd:enumeration value="tmRoot"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLCommonTimeNodeData"> + <xsd:sequence> + <xsd:element name="stCondLst" type="CT_TLTimeConditionList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="endCondLst" type="CT_TLTimeConditionList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="endSync" type="CT_TLTimeCondition" minOccurs="0" maxOccurs="1"/> + <xsd:element name="iterate" type="CT_TLIterateData" minOccurs="0" maxOccurs="1"/> + <xsd:element name="childTnLst" type="CT_TimeNodeList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="subTnLst" type="CT_TimeNodeList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="id" type="ST_TLTimeNodeID" use="optional"/> + <xsd:attribute name="presetID" type="xsd:int" use="optional"/> + <xsd:attribute name="presetClass" type="ST_TLTimeNodePresetClassType" use="optional"/> + <xsd:attribute name="presetSubtype" type="xsd:int" use="optional"/> + <xsd:attribute name="dur" type="ST_TLTime" use="optional"/> + <xsd:attribute name="repeatCount" type="ST_TLTime" use="optional" default="1000"/> + <xsd:attribute name="repeatDur" type="ST_TLTime" use="optional"/> + <xsd:attribute name="spd" type="a:ST_Percentage" use="optional" default="100%"/> + <xsd:attribute name="accel" type="a:ST_PositiveFixedPercentage" use="optional" default="0%"/> + <xsd:attribute name="decel" type="a:ST_PositiveFixedPercentage" use="optional" default="0%"/> + <xsd:attribute name="autoRev" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="restart" type="ST_TLTimeNodeRestartType" use="optional"/> + <xsd:attribute name="fill" type="ST_TLTimeNodeFillType" use="optional"/> + <xsd:attribute name="syncBehavior" type="ST_TLTimeNodeSyncType" use="optional"/> + <xsd:attribute name="tmFilter" type="xsd:string" use="optional"/> + <xsd:attribute name="evtFilter" type="xsd:string" use="optional"/> + <xsd:attribute name="display" type="xsd:boolean" use="optional"/> + <xsd:attribute name="masterRel" type="ST_TLTimeNodeMasterRelation" use="optional"/> + <xsd:attribute name="bldLvl" type="xsd:int" use="optional"/> + <xsd:attribute name="grpId" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="afterEffect" type="xsd:boolean" use="optional"/> + <xsd:attribute name="nodeType" type="ST_TLTimeNodeType" use="optional"/> + <xsd:attribute name="nodePh" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TLTimeNodeParallel"> + <xsd:sequence> + <xsd:element name="cTn" type="CT_TLCommonTimeNodeData" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_TLNextActionType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="seek"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TLPreviousActionType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="skipTimed"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLTimeNodeSequence"> + <xsd:sequence> + <xsd:element name="cTn" type="CT_TLCommonTimeNodeData" minOccurs="1" maxOccurs="1"/> + <xsd:element name="prevCondLst" type="CT_TLTimeConditionList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="nextCondLst" type="CT_TLTimeConditionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="concurrent" type="xsd:boolean" use="optional"/> + <xsd:attribute name="prevAc" type="ST_TLPreviousActionType" use="optional"/> + <xsd:attribute name="nextAc" type="ST_TLNextActionType" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TLTimeNodeExclusive"> + <xsd:sequence> + <xsd:element name="cTn" type="CT_TLCommonTimeNodeData" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TLBehaviorAttributeNameList"> + <xsd:sequence> + <xsd:element name="attrName" type="xsd:string" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_TLBehaviorAdditiveType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="base"/> + <xsd:enumeration value="sum"/> + <xsd:enumeration value="repl"/> + <xsd:enumeration value="mult"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TLBehaviorAccumulateType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="always"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TLBehaviorTransformType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="pt"/> + <xsd:enumeration value="img"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TLBehaviorOverrideType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="normal"/> + <xsd:enumeration value="childStyle"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLCommonBehaviorData"> + <xsd:sequence> + <xsd:element name="cTn" type="CT_TLCommonTimeNodeData" minOccurs="1" maxOccurs="1"/> + <xsd:element name="tgtEl" type="CT_TLTimeTargetElement" minOccurs="1" maxOccurs="1"/> + <xsd:element name="attrNameLst" type="CT_TLBehaviorAttributeNameList" minOccurs="0" + maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="additive" type="ST_TLBehaviorAdditiveType" use="optional"/> + <xsd:attribute name="accumulate" type="ST_TLBehaviorAccumulateType" use="optional"/> + <xsd:attribute name="xfrmType" type="ST_TLBehaviorTransformType" use="optional"/> + <xsd:attribute name="from" type="xsd:string" use="optional"/> + <xsd:attribute name="to" type="xsd:string" use="optional"/> + <xsd:attribute name="by" type="xsd:string" use="optional"/> + <xsd:attribute name="rctx" type="xsd:string" use="optional"/> + <xsd:attribute name="override" type="ST_TLBehaviorOverrideType" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TLAnimVariantBooleanVal"> + <xsd:attribute name="val" type="xsd:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TLAnimVariantIntegerVal"> + <xsd:attribute name="val" type="xsd:int" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TLAnimVariantFloatVal"> + <xsd:attribute name="val" type="xsd:float" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TLAnimVariantStringVal"> + <xsd:attribute name="val" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TLAnimVariant"> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="boolVal" type="CT_TLAnimVariantBooleanVal"/> + <xsd:element name="intVal" type="CT_TLAnimVariantIntegerVal"/> + <xsd:element name="fltVal" type="CT_TLAnimVariantFloatVal"/> + <xsd:element name="strVal" type="CT_TLAnimVariantStringVal"/> + <xsd:element name="clrVal" type="a:CT_Color"/> + </xsd:choice> + </xsd:complexType> + <xsd:simpleType name="ST_TLTimeAnimateValueTime"> + <xsd:union memberTypes="a:ST_PositiveFixedPercentage ST_TLTimeIndefinite"/> + </xsd:simpleType> + <xsd:complexType name="CT_TLTimeAnimateValue"> + <xsd:sequence> + <xsd:element name="val" type="CT_TLAnimVariant" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="tm" type="ST_TLTimeAnimateValueTime" use="optional" default="indefinite"/> + <xsd:attribute name="fmla" type="xsd:string" use="optional" default=""/> + </xsd:complexType> + <xsd:complexType name="CT_TLTimeAnimateValueList"> + <xsd:sequence> + <xsd:element name="tav" type="CT_TLTimeAnimateValue" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_TLAnimateBehaviorCalcMode"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="discrete"/> + <xsd:enumeration value="lin"/> + <xsd:enumeration value="fmla"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TLAnimateBehaviorValueType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="str"/> + <xsd:enumeration value="num"/> + <xsd:enumeration value="clr"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLAnimateBehavior"> + <xsd:sequence> + <xsd:element name="cBhvr" type="CT_TLCommonBehaviorData" minOccurs="1" maxOccurs="1"/> + <xsd:element name="tavLst" type="CT_TLTimeAnimateValueList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="by" type="xsd:string" use="optional"/> + <xsd:attribute name="from" type="xsd:string" use="optional"/> + <xsd:attribute name="to" type="xsd:string" use="optional"/> + <xsd:attribute name="calcmode" type="ST_TLAnimateBehaviorCalcMode" use="optional"/> + <xsd:attribute name="valueType" type="ST_TLAnimateBehaviorValueType" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TLByRgbColorTransform"> + <xsd:attribute name="r" type="a:ST_FixedPercentage" use="required"/> + <xsd:attribute name="g" type="a:ST_FixedPercentage" use="required"/> + <xsd:attribute name="b" type="a:ST_FixedPercentage" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TLByHslColorTransform"> + <xsd:attribute name="h" type="a:ST_Angle" use="required"/> + <xsd:attribute name="s" type="a:ST_FixedPercentage" use="required"/> + <xsd:attribute name="l" type="a:ST_FixedPercentage" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TLByAnimateColorTransform"> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="rgb" type="CT_TLByRgbColorTransform"/> + <xsd:element name="hsl" type="CT_TLByHslColorTransform"/> + </xsd:choice> + </xsd:complexType> + <xsd:simpleType name="ST_TLAnimateColorSpace"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="rgb"/> + <xsd:enumeration value="hsl"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TLAnimateColorDirection"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="cw"/> + <xsd:enumeration value="ccw"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLAnimateColorBehavior"> + <xsd:sequence> + <xsd:element name="cBhvr" type="CT_TLCommonBehaviorData" minOccurs="1" maxOccurs="1"/> + <xsd:element name="by" type="CT_TLByAnimateColorTransform" minOccurs="0" maxOccurs="1"/> + <xsd:element name="from" type="a:CT_Color" minOccurs="0" maxOccurs="1"/> + <xsd:element name="to" type="a:CT_Color" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="clrSpc" type="ST_TLAnimateColorSpace" use="optional"/> + <xsd:attribute name="dir" type="ST_TLAnimateColorDirection" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_TLAnimateEffectTransition"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="in"/> + <xsd:enumeration value="out"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLAnimateEffectBehavior"> + <xsd:sequence> + <xsd:element name="cBhvr" type="CT_TLCommonBehaviorData" minOccurs="1" maxOccurs="1"/> + <xsd:element name="progress" type="CT_TLAnimVariant" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="transition" type="ST_TLAnimateEffectTransition" default="in" use="optional"/> + <xsd:attribute name="filter" type="xsd:string" use="optional"/> + <xsd:attribute name="prLst" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_TLAnimateMotionBehaviorOrigin"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="parent"/> + <xsd:enumeration value="layout"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TLAnimateMotionPathEditMode"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="relative"/> + <xsd:enumeration value="fixed"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLPoint"> + <xsd:attribute name="x" type="a:ST_Percentage" use="required"/> + <xsd:attribute name="y" type="a:ST_Percentage" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TLAnimateMotionBehavior"> + <xsd:sequence> + <xsd:element name="cBhvr" type="CT_TLCommonBehaviorData" minOccurs="1" maxOccurs="1"/> + <xsd:element name="by" type="CT_TLPoint" minOccurs="0" maxOccurs="1"/> + <xsd:element name="from" type="CT_TLPoint" minOccurs="0" maxOccurs="1"/> + <xsd:element name="to" type="CT_TLPoint" minOccurs="0" maxOccurs="1"/> + <xsd:element name="rCtr" type="CT_TLPoint" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="origin" type="ST_TLAnimateMotionBehaviorOrigin" use="optional"/> + <xsd:attribute name="path" type="xsd:string" use="optional"/> + <xsd:attribute name="pathEditMode" type="ST_TLAnimateMotionPathEditMode" use="optional"/> + <xsd:attribute name="rAng" type="a:ST_Angle" use="optional"/> + <xsd:attribute name="ptsTypes" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TLAnimateRotationBehavior"> + <xsd:sequence> + <xsd:element name="cBhvr" type="CT_TLCommonBehaviorData" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="by" type="a:ST_Angle" use="optional"/> + <xsd:attribute name="from" type="a:ST_Angle" use="optional"/> + <xsd:attribute name="to" type="a:ST_Angle" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TLAnimateScaleBehavior"> + <xsd:sequence> + <xsd:element name="cBhvr" type="CT_TLCommonBehaviorData" minOccurs="1" maxOccurs="1"/> + <xsd:element name="by" type="CT_TLPoint" minOccurs="0" maxOccurs="1"/> + <xsd:element name="from" type="CT_TLPoint" minOccurs="0" maxOccurs="1"/> + <xsd:element name="to" type="CT_TLPoint" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="zoomContents" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_TLCommandType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="evt"/> + <xsd:enumeration value="call"/> + <xsd:enumeration value="verb"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLCommandBehavior"> + <xsd:sequence> + <xsd:element name="cBhvr" type="CT_TLCommonBehaviorData" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute type="ST_TLCommandType" name="type" use="optional"/> + <xsd:attribute name="cmd" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TLSetBehavior"> + <xsd:sequence> + <xsd:element name="cBhvr" type="CT_TLCommonBehaviorData" minOccurs="1" maxOccurs="1"/> + <xsd:element name="to" type="CT_TLAnimVariant" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TLCommonMediaNodeData"> + <xsd:sequence> + <xsd:element name="cTn" type="CT_TLCommonTimeNodeData" minOccurs="1" maxOccurs="1"/> + <xsd:element name="tgtEl" type="CT_TLTimeTargetElement" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="vol" type="a:ST_PositiveFixedPercentage" default="50%" use="optional"/> + <xsd:attribute name="mute" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="numSld" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute name="showWhenStopped" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_TLMediaNodeAudio"> + <xsd:sequence> + <xsd:element name="cMediaNode" type="CT_TLCommonMediaNodeData" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="isNarration" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_TLMediaNodeVideo"> + <xsd:sequence> + <xsd:element name="cMediaNode" type="CT_TLCommonMediaNodeData" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="fullScrn" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:attributeGroup name="AG_TLBuild"> + <xsd:attribute name="spid" type="a:ST_DrawingElementId" use="required"/> + <xsd:attribute name="grpId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="uiExpand" type="xsd:boolean" use="optional" default="false"/> + </xsd:attributeGroup> + <xsd:complexType name="CT_TLTemplate"> + <xsd:sequence> + <xsd:element name="tnLst" type="CT_TimeNodeList" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="lvl" type="xsd:unsignedInt" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_TLTemplateList"> + <xsd:sequence> + <xsd:element name="tmpl" type="CT_TLTemplate" minOccurs="0" maxOccurs="9"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_TLParaBuildType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="allAtOnce"/> + <xsd:enumeration value="p"/> + <xsd:enumeration value="cust"/> + <xsd:enumeration value="whole"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLBuildParagraph"> + <xsd:sequence> + <xsd:element name="tmplLst" type="CT_TLTemplateList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_TLBuild"/> + <xsd:attribute name="build" type="ST_TLParaBuildType" use="optional" default="whole"/> + <xsd:attribute name="bldLvl" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute name="animBg" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="autoUpdateAnimBg" type="xsd:boolean" default="true" use="optional"/> + <xsd:attribute name="rev" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="advAuto" type="ST_TLTime" use="optional" default="indefinite"/> + </xsd:complexType> + <xsd:simpleType name="ST_TLDiagramBuildType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="whole"/> + <xsd:enumeration value="depthByNode"/> + <xsd:enumeration value="depthByBranch"/> + <xsd:enumeration value="breadthByNode"/> + <xsd:enumeration value="breadthByLvl"/> + <xsd:enumeration value="cw"/> + <xsd:enumeration value="cwIn"/> + <xsd:enumeration value="cwOut"/> + <xsd:enumeration value="ccw"/> + <xsd:enumeration value="ccwIn"/> + <xsd:enumeration value="ccwOut"/> + <xsd:enumeration value="inByRing"/> + <xsd:enumeration value="outByRing"/> + <xsd:enumeration value="up"/> + <xsd:enumeration value="down"/> + <xsd:enumeration value="allAtOnce"/> + <xsd:enumeration value="cust"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLBuildDiagram"> + <xsd:attributeGroup ref="AG_TLBuild"/> + <xsd:attribute name="bld" type="ST_TLDiagramBuildType" use="optional" default="whole"/> + </xsd:complexType> + <xsd:simpleType name="ST_TLOleChartBuildType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="allAtOnce"/> + <xsd:enumeration value="series"/> + <xsd:enumeration value="category"/> + <xsd:enumeration value="seriesEl"/> + <xsd:enumeration value="categoryEl"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TLOleBuildChart"> + <xsd:attributeGroup ref="AG_TLBuild"/> + <xsd:attribute name="bld" type="ST_TLOleChartBuildType" use="optional" default="allAtOnce"/> + <xsd:attribute name="animBg" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_TLGraphicalObjectBuild"> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="bldAsOne" type="CT_Empty"/> + <xsd:element name="bldSub" type="a:CT_AnimationGraphicalObjectBuildProperties"/> + </xsd:choice> + <xsd:attributeGroup ref="AG_TLBuild"/> + </xsd:complexType> + <xsd:complexType name="CT_BuildList"> + <xsd:choice minOccurs="1" maxOccurs="unbounded"> + <xsd:element name="bldP" type="CT_TLBuildParagraph"/> + <xsd:element name="bldDgm" type="CT_TLBuildDiagram"/> + <xsd:element name="bldOleChart" type="CT_TLOleBuildChart"/> + <xsd:element name="bldGraphic" type="CT_TLGraphicalObjectBuild"/> + </xsd:choice> + </xsd:complexType> + <xsd:complexType name="CT_SlideTiming"> + <xsd:sequence> + <xsd:element name="tnLst" type="CT_TimeNodeList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bldLst" type="CT_BuildList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Empty"/> + <xsd:simpleType name="ST_Name"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="ST_Direction"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="horz"/> + <xsd:enumeration value="vert"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Index"> + <xsd:restriction base="xsd:unsignedInt"/> + </xsd:simpleType> + <xsd:complexType name="CT_IndexRange"> + <xsd:attribute name="st" type="ST_Index" use="required"/> + <xsd:attribute name="end" type="ST_Index" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SlideRelationshipListEntry"> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SlideRelationshipList"> + <xsd:sequence> + <xsd:element name="sld" type="CT_SlideRelationshipListEntry" minOccurs="0" + maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CustomShowId"> + <xsd:attribute name="id" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:group name="EG_SlideListChoice"> + <xsd:choice> + <xsd:element name="sldAll" type="CT_Empty"/> + <xsd:element name="sldRg" type="CT_IndexRange"/> + <xsd:element name="custShow" type="CT_CustomShowId"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_CustomerData"> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TagsData"> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomerDataList"> + <xsd:sequence minOccurs="0" maxOccurs="1"> + <xsd:element name="custData" type="CT_CustomerData" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="tags" type="CT_TagsData" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Extension"> + <xsd:sequence> + <xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="uri" type="xsd:token" use="required"/> + </xsd:complexType> + <xsd:group name="EG_ExtensionList"> + <xsd:sequence> + <xsd:element name="ext" type="CT_Extension" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_ExtensionList"> + <xsd:sequence> + <xsd:group ref="EG_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ExtensionListModify"> + <xsd:sequence> + <xsd:group ref="EG_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="mod" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_CommentAuthor"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="name" type="ST_Name" use="required"/> + <xsd:attribute name="initials" type="ST_Name" use="required"/> + <xsd:attribute name="lastIdx" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="clrIdx" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CommentAuthorList"> + <xsd:sequence> + <xsd:element name="cmAuthor" type="CT_CommentAuthor" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="cmAuthorLst" type="CT_CommentAuthorList"/> + <xsd:complexType name="CT_Comment"> + <xsd:sequence> + <xsd:element name="pos" type="a:CT_Point2D" minOccurs="1" maxOccurs="1"/> + <xsd:element name="text" type="xsd:string" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="authorId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="dt" type="xsd:dateTime" use="optional"/> + <xsd:attribute name="idx" type="ST_Index" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CommentList"> + <xsd:sequence> + <xsd:element name="cm" type="CT_Comment" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="cmLst" type="CT_CommentList"/> + <xsd:attributeGroup name="AG_Ole"> + <xsd:attribute name="spid" type="a:ST_ShapeID" use="optional"/> + <xsd:attribute name="name" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="showAsIcon" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute ref="r:id" use="optional"/> + <xsd:attribute name="imgW" type="a:ST_PositiveCoordinate32" use="optional"/> + <xsd:attribute name="imgH" type="a:ST_PositiveCoordinate32" use="optional"/> + </xsd:attributeGroup> + <xsd:simpleType name="ST_OleObjectFollowColorScheme"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="full"/> + <xsd:enumeration value="textAndBackground"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_OleObjectEmbed"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="followColorScheme" type="ST_OleObjectFollowColorScheme" use="optional" + default="none"/> + </xsd:complexType> + <xsd:complexType name="CT_OleObjectLink"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="updateAutomatic" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_OleObject"> + <xsd:sequence> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="embed" type="CT_OleObjectEmbed"/> + <xsd:element name="link" type="CT_OleObjectLink"/> + </xsd:choice> + <xsd:element name="pic" type="CT_Picture" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_Ole"/> + <xsd:attribute name="progId" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:element name="oleObj" type="CT_OleObject"/> + <xsd:complexType name="CT_Control"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pic" type="CT_Picture" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_Ole"/> + </xsd:complexType> + <xsd:complexType name="CT_ControlList"> + <xsd:sequence> + <xsd:element name="control" type="CT_Control" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_SlideId"> + <xsd:restriction base="xsd:unsignedInt"> + <xsd:minInclusive value="256"/> + <xsd:maxExclusive value="2147483648"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SlideIdListEntry"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="id" type="ST_SlideId" use="required"/> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SlideIdList"> + <xsd:sequence> + <xsd:element name="sldId" type="CT_SlideIdListEntry" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_SlideMasterId"> + <xsd:restriction base="xsd:unsignedInt"> + <xsd:minInclusive value="2147483648"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SlideMasterIdListEntry"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="id" type="ST_SlideMasterId" use="optional"/> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SlideMasterIdList"> + <xsd:sequence> + <xsd:element name="sldMasterId" type="CT_SlideMasterIdListEntry" minOccurs="0" + maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_NotesMasterIdListEntry"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_NotesMasterIdList"> + <xsd:sequence> + <xsd:element name="notesMasterId" type="CT_NotesMasterIdListEntry" minOccurs="0" maxOccurs="1" + /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_HandoutMasterIdListEntry"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_HandoutMasterIdList"> + <xsd:sequence> + <xsd:element name="handoutMasterId" type="CT_HandoutMasterIdListEntry" minOccurs="0" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_EmbeddedFontDataId"> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_EmbeddedFontListEntry"> + <xsd:sequence> + <xsd:element name="font" type="a:CT_TextFont" minOccurs="1" maxOccurs="1"/> + <xsd:element name="regular" type="CT_EmbeddedFontDataId" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bold" type="CT_EmbeddedFontDataId" minOccurs="0" maxOccurs="1"/> + <xsd:element name="italic" type="CT_EmbeddedFontDataId" minOccurs="0" maxOccurs="1"/> + <xsd:element name="boldItalic" type="CT_EmbeddedFontDataId" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_EmbeddedFontList"> + <xsd:sequence> + <xsd:element name="embeddedFont" type="CT_EmbeddedFontListEntry" minOccurs="0" + maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SmartTags"> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomShow"> + <xsd:sequence> + <xsd:element name="sldLst" type="CT_SlideRelationshipList" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="name" type="ST_Name" use="required"/> + <xsd:attribute name="id" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomShowList"> + <xsd:sequence> + <xsd:element name="custShow" type="CT_CustomShow" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_PhotoAlbumLayout"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="fitToSlide"/> + <xsd:enumeration value="1pic"/> + <xsd:enumeration value="2pic"/> + <xsd:enumeration value="4pic"/> + <xsd:enumeration value="1picTitle"/> + <xsd:enumeration value="2picTitle"/> + <xsd:enumeration value="4picTitle"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PhotoAlbumFrameShape"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="frameStyle1"/> + <xsd:enumeration value="frameStyle2"/> + <xsd:enumeration value="frameStyle3"/> + <xsd:enumeration value="frameStyle4"/> + <xsd:enumeration value="frameStyle5"/> + <xsd:enumeration value="frameStyle6"/> + <xsd:enumeration value="frameStyle7"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PhotoAlbum"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="bw" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showCaptions" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="layout" type="ST_PhotoAlbumLayout" use="optional" default="fitToSlide"/> + <xsd:attribute name="frame" type="ST_PhotoAlbumFrameShape" use="optional" default="frameStyle1" + /> + </xsd:complexType> + <xsd:simpleType name="ST_SlideSizeCoordinate"> + <xsd:restriction base="a:ST_PositiveCoordinate32"> + <xsd:minInclusive value="914400"/> + <xsd:maxInclusive value="51206400"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_SlideSizeType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="screen4x3"/> + <xsd:enumeration value="letter"/> + <xsd:enumeration value="A4"/> + <xsd:enumeration value="35mm"/> + <xsd:enumeration value="overhead"/> + <xsd:enumeration value="banner"/> + <xsd:enumeration value="custom"/> + <xsd:enumeration value="ledger"/> + <xsd:enumeration value="A3"/> + <xsd:enumeration value="B4ISO"/> + <xsd:enumeration value="B5ISO"/> + <xsd:enumeration value="B4JIS"/> + <xsd:enumeration value="B5JIS"/> + <xsd:enumeration value="hagakiCard"/> + <xsd:enumeration value="screen16x9"/> + <xsd:enumeration value="screen16x10"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SlideSize"> + <xsd:attribute name="cx" type="ST_SlideSizeCoordinate" use="required"/> + <xsd:attribute name="cy" type="ST_SlideSizeCoordinate" use="required"/> + <xsd:attribute name="type" type="ST_SlideSizeType" use="optional" default="custom"/> + </xsd:complexType> + <xsd:complexType name="CT_Kinsoku"> + <xsd:attribute name="lang" type="xsd:string" use="optional"/> + <xsd:attribute name="invalStChars" type="xsd:string" use="required"/> + <xsd:attribute name="invalEndChars" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_BookmarkIdSeed"> + <xsd:restriction base="xsd:unsignedInt"> + <xsd:minInclusive value="1"/> + <xsd:maxExclusive value="2147483648"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_ModifyVerifier"> + <xsd:attribute name="algorithmName" type="xsd:string" use="optional"/> + <xsd:attribute name="hashValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="saltValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="spinValue" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="cryptProviderType" type="s:ST_CryptProv" use="optional"/> + <xsd:attribute name="cryptAlgorithmClass" type="s:ST_AlgClass" use="optional"/> + <xsd:attribute name="cryptAlgorithmType" type="s:ST_AlgType" use="optional"/> + <xsd:attribute name="cryptAlgorithmSid" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="spinCount" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="saltData" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="hashData" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="cryptProvider" type="xsd:string" use="optional"/> + <xsd:attribute name="algIdExt" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="algIdExtSource" type="xsd:string" use="optional"/> + <xsd:attribute name="cryptProviderTypeExt" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="cryptProviderTypeExtSource" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Presentation"> + <xsd:sequence> + <xsd:element name="sldMasterIdLst" type="CT_SlideMasterIdList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="notesMasterIdLst" type="CT_NotesMasterIdList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="handoutMasterIdLst" type="CT_HandoutMasterIdList" minOccurs="0" + maxOccurs="1"/> + <xsd:element name="sldIdLst" type="CT_SlideIdList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sldSz" type="CT_SlideSize" minOccurs="0" maxOccurs="1"/> + <xsd:element name="notesSz" type="a:CT_PositiveSize2D" minOccurs="1" maxOccurs="1"/> + <xsd:element name="smartTags" type="CT_SmartTags" minOccurs="0" maxOccurs="1"/> + <xsd:element name="embeddedFontLst" type="CT_EmbeddedFontList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="custShowLst" type="CT_CustomShowList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="photoAlbum" type="CT_PhotoAlbum" minOccurs="0" maxOccurs="1"/> + <xsd:element name="custDataLst" type="CT_CustomerDataList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="kinsoku" type="CT_Kinsoku" minOccurs="0"/> + <xsd:element name="defaultTextStyle" type="a:CT_TextListStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="modifyVerifier" type="CT_ModifyVerifier" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="serverZoom" type="a:ST_Percentage" use="optional" default="50%"/> + <xsd:attribute name="firstSlideNum" type="xsd:int" use="optional" default="1"/> + <xsd:attribute name="showSpecialPlsOnTitleSld" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="rtl" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="removePersonalInfoOnSave" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="compatMode" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="strictFirstAndLastChars" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="embedTrueTypeFonts" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="saveSubsetFonts" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="autoCompressPictures" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="bookmarkIdSeed" type="ST_BookmarkIdSeed" use="optional" default="1"/> + <xsd:attribute name="conformance" type="s:ST_ConformanceClass"/> + </xsd:complexType> + <xsd:element name="presentation" type="CT_Presentation"/> + <xsd:complexType name="CT_HtmlPublishProperties"> + <xsd:sequence> + <xsd:group ref="EG_SlideListChoice" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="showSpeakerNotes" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="target" type="xsd:string" use="optional"/> + <xsd:attribute name="title" type="xsd:string" use="optional" default=""/> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_WebColorType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="browser"/> + <xsd:enumeration value="presentationText"/> + <xsd:enumeration value="presentationAccent"/> + <xsd:enumeration value="whiteTextOnBlack"/> + <xsd:enumeration value="blackTextOnWhite"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_WebScreenSize"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="544x376"/> + <xsd:enumeration value="640x480"/> + <xsd:enumeration value="720x512"/> + <xsd:enumeration value="800x600"/> + <xsd:enumeration value="1024x768"/> + <xsd:enumeration value="1152x882"/> + <xsd:enumeration value="1152x900"/> + <xsd:enumeration value="1280x1024"/> + <xsd:enumeration value="1600x1200"/> + <xsd:enumeration value="1800x1400"/> + <xsd:enumeration value="1920x1200"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_WebEncoding"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:complexType name="CT_WebProperties"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="showAnimation" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="resizeGraphics" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="allowPng" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="relyOnVml" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="organizeInFolders" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="useLongFilenames" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="imgSz" type="ST_WebScreenSize" use="optional" default="800x600"/> + <xsd:attribute name="encoding" type="ST_WebEncoding" use="optional" default=""/> + <xsd:attribute name="clr" type="ST_WebColorType" use="optional" default="whiteTextOnBlack"/> + </xsd:complexType> + <xsd:simpleType name="ST_PrintWhat"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="slides"/> + <xsd:enumeration value="handouts1"/> + <xsd:enumeration value="handouts2"/> + <xsd:enumeration value="handouts3"/> + <xsd:enumeration value="handouts4"/> + <xsd:enumeration value="handouts6"/> + <xsd:enumeration value="handouts9"/> + <xsd:enumeration value="notes"/> + <xsd:enumeration value="outline"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PrintColorMode"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="bw"/> + <xsd:enumeration value="gray"/> + <xsd:enumeration value="clr"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PrintProperties"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="prnWhat" type="ST_PrintWhat" use="optional" default="slides"/> + <xsd:attribute name="clrMode" type="ST_PrintColorMode" use="optional" default="clr"/> + <xsd:attribute name="hiddenSlides" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="scaleToFitPaper" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="frameSlides" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_ShowInfoBrowse"> + <xsd:attribute name="showScrollbar" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_ShowInfoKiosk"> + <xsd:attribute name="restart" type="xsd:unsignedInt" use="optional" default="300000"/> + </xsd:complexType> + <xsd:group name="EG_ShowType"> + <xsd:choice> + <xsd:element name="present" type="CT_Empty"/> + <xsd:element name="browse" type="CT_ShowInfoBrowse"/> + <xsd:element name="kiosk" type="CT_ShowInfoKiosk"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_ShowProperties"> + <xsd:sequence minOccurs="0" maxOccurs="1"> + <xsd:group ref="EG_ShowType" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_SlideListChoice" minOccurs="0" maxOccurs="1"/> + <xsd:element name="penClr" type="a:CT_Color" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="loop" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showNarration" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showAnimation" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="useTimings" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_PresentationProperties"> + <xsd:sequence> + <xsd:element name="htmlPubPr" type="CT_HtmlPublishProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="webPr" type="CT_WebProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="prnPr" type="CT_PrintProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="showPr" type="CT_ShowProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="clrMru" type="a:CT_ColorMRU" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="presentationPr" type="CT_PresentationProperties"/> + <xsd:complexType name="CT_HeaderFooter"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="sldNum" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="hdr" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="ftr" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="dt" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:simpleType name="ST_PlaceholderType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="title"/> + <xsd:enumeration value="body"/> + <xsd:enumeration value="ctrTitle"/> + <xsd:enumeration value="subTitle"/> + <xsd:enumeration value="dt"/> + <xsd:enumeration value="sldNum"/> + <xsd:enumeration value="ftr"/> + <xsd:enumeration value="hdr"/> + <xsd:enumeration value="obj"/> + <xsd:enumeration value="chart"/> + <xsd:enumeration value="tbl"/> + <xsd:enumeration value="clipArt"/> + <xsd:enumeration value="dgm"/> + <xsd:enumeration value="media"/> + <xsd:enumeration value="sldImg"/> + <xsd:enumeration value="pic"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PlaceholderSize"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="full"/> + <xsd:enumeration value="half"/> + <xsd:enumeration value="quarter"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Placeholder"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="type" type="ST_PlaceholderType" use="optional" default="obj"/> + <xsd:attribute name="orient" type="ST_Direction" use="optional" default="horz"/> + <xsd:attribute name="sz" type="ST_PlaceholderSize" use="optional" default="full"/> + <xsd:attribute name="idx" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="hasCustomPrompt" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_ApplicationNonVisualDrawingProps"> + <xsd:sequence> + <xsd:element name="ph" type="CT_Placeholder" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="a:EG_Media" minOccurs="0" maxOccurs="1"/> + <xsd:element name="custDataLst" type="CT_CustomerDataList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="isPhoto" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="userDrawn" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_ShapeNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvSpPr" type="a:CT_NonVisualDrawingShapeProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="nvPr" type="CT_ApplicationNonVisualDrawingProps" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Shape"> + <xsd:sequence> + <xsd:element name="nvSpPr" type="CT_ShapeNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txBody" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="useBgFill" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_ConnectorNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvCxnSpPr" type="a:CT_NonVisualConnectorProperties" minOccurs="1" + maxOccurs="1"/> + <xsd:element name="nvPr" type="CT_ApplicationNonVisualDrawingProps" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Connector"> + <xsd:sequence> + <xsd:element name="nvCxnSpPr" type="CT_ConnectorNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PictureNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvPicPr" type="a:CT_NonVisualPictureProperties" minOccurs="1" + maxOccurs="1"/> + <xsd:element name="nvPr" type="CT_ApplicationNonVisualDrawingProps" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Picture"> + <xsd:sequence> + <xsd:element name="nvPicPr" type="CT_PictureNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="blipFill" type="a:CT_BlipFillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GraphicalObjectFrameNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties" + minOccurs="1" maxOccurs="1"/> + <xsd:element name="nvPr" type="CT_ApplicationNonVisualDrawingProps" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GraphicalObjectFrame"> + <xsd:sequence> + <xsd:element name="nvGraphicFramePr" type="CT_GraphicalObjectFrameNonVisual" minOccurs="1" + maxOccurs="1"/> + <xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="1" maxOccurs="1"/> + <xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="bwMode" type="a:ST_BlackWhiteMode" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_GroupShapeNonVisual"> + <xsd:sequence> + <xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cNvGrpSpPr" type="a:CT_NonVisualGroupDrawingShapeProps" minOccurs="1" + maxOccurs="1"/> + <xsd:element name="nvPr" type="CT_ApplicationNonVisualDrawingProps" minOccurs="1" + maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GroupShape"> + <xsd:sequence> + <xsd:element name="nvGrpSpPr" type="CT_GroupShapeNonVisual" minOccurs="1" maxOccurs="1"/> + <xsd:element name="grpSpPr" type="a:CT_GroupShapeProperties" minOccurs="1" maxOccurs="1"/> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="sp" type="CT_Shape"/> + <xsd:element name="grpSp" type="CT_GroupShape"/> + <xsd:element name="graphicFrame" type="CT_GraphicalObjectFrame"/> + <xsd:element name="cxnSp" type="CT_Connector"/> + <xsd:element name="pic" type="CT_Picture"/> + <xsd:element name="contentPart" type="CT_Rel"/> + </xsd:choice> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Rel"> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:group name="EG_TopLevelSlide"> + <xsd:sequence> + <xsd:element name="clrMap" type="a:CT_ColorMapping" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:group> + <xsd:group name="EG_ChildSlide"> + <xsd:sequence> + <xsd:element name="clrMapOvr" type="a:CT_ColorMappingOverride" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:group> + <xsd:attributeGroup name="AG_ChildSlide"> + <xsd:attribute name="showMasterSp" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="showMasterPhAnim" type="xsd:boolean" use="optional" default="true"/> + </xsd:attributeGroup> + <xsd:complexType name="CT_BackgroundProperties"> + <xsd:sequence> + <xsd:group ref="a:EG_FillProperties" minOccurs="1" maxOccurs="1"/> + <xsd:group ref="a:EG_EffectProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="shadeToTitle" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:group name="EG_Background"> + <xsd:choice> + <xsd:element name="bgPr" type="CT_BackgroundProperties"/> + <xsd:element name="bgRef" type="a:CT_StyleMatrixReference"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_Background"> + <xsd:sequence> + <xsd:group ref="EG_Background"/> + </xsd:sequence> + <xsd:attribute name="bwMode" type="a:ST_BlackWhiteMode" use="optional" default="white"/> + </xsd:complexType> + <xsd:complexType name="CT_CommonSlideData"> + <xsd:sequence> + <xsd:element name="bg" type="CT_Background" minOccurs="0" maxOccurs="1"/> + <xsd:element name="spTree" type="CT_GroupShape" minOccurs="1" maxOccurs="1"/> + <xsd:element name="custDataLst" type="CT_CustomerDataList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="controls" type="CT_ControlList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="optional" default=""/> + </xsd:complexType> + <xsd:complexType name="CT_Slide"> + <xsd:sequence minOccurs="1" maxOccurs="1"> + <xsd:element name="cSld" type="CT_CommonSlideData" minOccurs="1" maxOccurs="1"/> + <xsd:group ref="EG_ChildSlide" minOccurs="0" maxOccurs="1"/> + <xsd:element name="transition" type="CT_SlideTransition" minOccurs="0" maxOccurs="1"/> + <xsd:element name="timing" type="CT_SlideTiming" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_ChildSlide"/> + <xsd:attribute name="show" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:element name="sld" type="CT_Slide"/> + <xsd:simpleType name="ST_SlideLayoutType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="title"/> + <xsd:enumeration value="tx"/> + <xsd:enumeration value="twoColTx"/> + <xsd:enumeration value="tbl"/> + <xsd:enumeration value="txAndChart"/> + <xsd:enumeration value="chartAndTx"/> + <xsd:enumeration value="dgm"/> + <xsd:enumeration value="chart"/> + <xsd:enumeration value="txAndClipArt"/> + <xsd:enumeration value="clipArtAndTx"/> + <xsd:enumeration value="titleOnly"/> + <xsd:enumeration value="blank"/> + <xsd:enumeration value="txAndObj"/> + <xsd:enumeration value="objAndTx"/> + <xsd:enumeration value="objOnly"/> + <xsd:enumeration value="obj"/> + <xsd:enumeration value="txAndMedia"/> + <xsd:enumeration value="mediaAndTx"/> + <xsd:enumeration value="objOverTx"/> + <xsd:enumeration value="txOverObj"/> + <xsd:enumeration value="txAndTwoObj"/> + <xsd:enumeration value="twoObjAndTx"/> + <xsd:enumeration value="twoObjOverTx"/> + <xsd:enumeration value="fourObj"/> + <xsd:enumeration value="vertTx"/> + <xsd:enumeration value="clipArtAndVertTx"/> + <xsd:enumeration value="vertTitleAndTx"/> + <xsd:enumeration value="vertTitleAndTxOverChart"/> + <xsd:enumeration value="twoObj"/> + <xsd:enumeration value="objAndTwoObj"/> + <xsd:enumeration value="twoObjAndObj"/> + <xsd:enumeration value="cust"/> + <xsd:enumeration value="secHead"/> + <xsd:enumeration value="twoTxTwoObj"/> + <xsd:enumeration value="objTx"/> + <xsd:enumeration value="picTx"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SlideLayout"> + <xsd:sequence minOccurs="1" maxOccurs="1"> + <xsd:element name="cSld" type="CT_CommonSlideData" minOccurs="1" maxOccurs="1"/> + <xsd:group ref="EG_ChildSlide" minOccurs="0" maxOccurs="1"/> + <xsd:element name="transition" type="CT_SlideTransition" minOccurs="0" maxOccurs="1"/> + <xsd:element name="timing" type="CT_SlideTiming" minOccurs="0" maxOccurs="1"/> + <xsd:element name="hf" type="CT_HeaderFooter" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_ChildSlide"/> + <xsd:attribute name="matchingName" type="xsd:string" use="optional" default=""/> + <xsd:attribute name="type" type="ST_SlideLayoutType" use="optional" default="cust"/> + <xsd:attribute name="preserve" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="userDrawn" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:element name="sldLayout" type="CT_SlideLayout"/> + <xsd:complexType name="CT_SlideMasterTextStyles"> + <xsd:sequence> + <xsd:element name="titleStyle" type="a:CT_TextListStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bodyStyle" type="a:CT_TextListStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="otherStyle" type="a:CT_TextListStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_SlideLayoutId"> + <xsd:restriction base="xsd:unsignedInt"> + <xsd:minInclusive value="2147483648"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SlideLayoutIdListEntry"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="id" type="ST_SlideLayoutId" use="optional"/> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SlideLayoutIdList"> + <xsd:sequence> + <xsd:element name="sldLayoutId" type="CT_SlideLayoutIdListEntry" minOccurs="0" + maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SlideMaster"> + <xsd:sequence minOccurs="1" maxOccurs="1"> + <xsd:element name="cSld" type="CT_CommonSlideData" minOccurs="1" maxOccurs="1"/> + <xsd:group ref="EG_TopLevelSlide" minOccurs="1" maxOccurs="1"/> + <xsd:element name="sldLayoutIdLst" type="CT_SlideLayoutIdList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="transition" type="CT_SlideTransition" minOccurs="0" maxOccurs="1"/> + <xsd:element name="timing" type="CT_SlideTiming" minOccurs="0" maxOccurs="1"/> + <xsd:element name="hf" type="CT_HeaderFooter" minOccurs="0" maxOccurs="1"/> + <xsd:element name="txStyles" type="CT_SlideMasterTextStyles" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="preserve" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:element name="sldMaster" type="CT_SlideMaster"/> + <xsd:complexType name="CT_HandoutMaster"> + <xsd:sequence> + <xsd:element name="cSld" type="CT_CommonSlideData" minOccurs="1" maxOccurs="1"/> + <xsd:group ref="EG_TopLevelSlide" minOccurs="1" maxOccurs="1"/> + <xsd:element name="hf" type="CT_HeaderFooter" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="handoutMaster" type="CT_HandoutMaster"/> + <xsd:complexType name="CT_NotesMaster"> + <xsd:sequence> + <xsd:element name="cSld" type="CT_CommonSlideData" minOccurs="1" maxOccurs="1"/> + <xsd:group ref="EG_TopLevelSlide" minOccurs="1" maxOccurs="1"/> + <xsd:element name="hf" type="CT_HeaderFooter" minOccurs="0" maxOccurs="1"/> + <xsd:element name="notesStyle" type="a:CT_TextListStyle" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="notesMaster" type="CT_NotesMaster"/> + <xsd:complexType name="CT_NotesSlide"> + <xsd:sequence minOccurs="1" maxOccurs="1"> + <xsd:element name="cSld" type="CT_CommonSlideData" minOccurs="1" maxOccurs="1"/> + <xsd:group ref="EG_ChildSlide" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionListModify" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_ChildSlide"/> + </xsd:complexType> + <xsd:element name="notes" type="CT_NotesSlide"/> + <xsd:complexType name="CT_SlideSyncProperties"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="serverSldId" type="xsd:string" use="required"/> + <xsd:attribute name="serverSldModifiedTime" type="xsd:dateTime" use="required"/> + <xsd:attribute name="clientInsertedTime" type="xsd:dateTime" use="required"/> + </xsd:complexType> + <xsd:element name="sldSyncPr" type="CT_SlideSyncProperties"/> + <xsd:complexType name="CT_StringTag"> + <xsd:attribute name="name" type="xsd:string" use="required"/> + <xsd:attribute name="val" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TagList"> + <xsd:sequence> + <xsd:element name="tag" type="CT_StringTag" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="tagLst" type="CT_TagList"/> + <xsd:simpleType name="ST_SplitterBarState"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="minimized"/> + <xsd:enumeration value="restored"/> + <xsd:enumeration value="maximized"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ViewType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="sldView"/> + <xsd:enumeration value="sldMasterView"/> + <xsd:enumeration value="notesView"/> + <xsd:enumeration value="handoutView"/> + <xsd:enumeration value="notesMasterView"/> + <xsd:enumeration value="outlineView"/> + <xsd:enumeration value="sldSorterView"/> + <xsd:enumeration value="sldThumbnailView"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_NormalViewPortion"> + <xsd:attribute name="sz" type="a:ST_PositiveFixedPercentage" use="required"/> + <xsd:attribute name="autoAdjust" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_NormalViewProperties"> + <xsd:sequence> + <xsd:element name="restoredLeft" type="CT_NormalViewPortion" minOccurs="1" maxOccurs="1"/> + <xsd:element name="restoredTop" type="CT_NormalViewPortion" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="showOutlineIcons" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="snapVertSplitter" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="vertBarState" type="ST_SplitterBarState" use="optional" default="restored"/> + <xsd:attribute name="horzBarState" type="ST_SplitterBarState" use="optional" default="restored"/> + <xsd:attribute name="preferSingleView" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_CommonViewProperties"> + <xsd:sequence> + <xsd:element name="scale" type="a:CT_Scale2D" minOccurs="1" maxOccurs="1"/> + <xsd:element name="origin" type="a:CT_Point2D" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="varScale" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_NotesTextViewProperties"> + <xsd:sequence minOccurs="1" maxOccurs="1"> + <xsd:element name="cViewPr" type="CT_CommonViewProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_OutlineViewSlideEntry"> + <xsd:attribute ref="r:id" use="required"/> + <xsd:attribute name="collapse" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_OutlineViewSlideList"> + <xsd:sequence> + <xsd:element name="sld" type="CT_OutlineViewSlideEntry" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_OutlineViewProperties"> + <xsd:sequence minOccurs="1" maxOccurs="1"> + <xsd:element name="cViewPr" type="CT_CommonViewProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="sldLst" type="CT_OutlineViewSlideList" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SlideSorterViewProperties"> + <xsd:sequence minOccurs="1" maxOccurs="1"> + <xsd:element name="cViewPr" type="CT_CommonViewProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="showFormatting" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_Guide"> + <xsd:attribute name="orient" type="ST_Direction" use="optional" default="vert"/> + <xsd:attribute name="pos" type="a:ST_Coordinate32" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_GuideList"> + <xsd:sequence minOccurs="0" maxOccurs="1"> + <xsd:element name="guide" type="CT_Guide" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CommonSlideViewProperties"> + <xsd:sequence> + <xsd:element name="cViewPr" type="CT_CommonViewProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="guideLst" type="CT_GuideList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="snapToGrid" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="snapToObjects" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showGuides" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_SlideViewProperties"> + <xsd:sequence> + <xsd:element name="cSldViewPr" type="CT_CommonSlideViewProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_NotesViewProperties"> + <xsd:sequence> + <xsd:element name="cSldViewPr" type="CT_CommonSlideViewProperties" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ViewProperties"> + <xsd:sequence minOccurs="0" maxOccurs="1"> + <xsd:element name="normalViewPr" type="CT_NormalViewProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="slideViewPr" type="CT_SlideViewProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="outlineViewPr" type="CT_OutlineViewProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="notesTextViewPr" type="CT_NotesTextViewProperties" minOccurs="0" + maxOccurs="1"/> + <xsd:element name="sorterViewPr" type="CT_SlideSorterViewProperties" minOccurs="0" + maxOccurs="1"/> + <xsd:element name="notesViewPr" type="CT_NotesViewProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="gridSpacing" type="a:CT_PositiveSize2D" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="lastView" type="ST_ViewType" use="optional" default="sldView"/> + <xsd:attribute name="showComments" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:element name="viewPr" type="CT_ViewProperties"/> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd new file mode 100644 index 0000000..c20f3bf --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/officeDocument/2006/characteristics" + targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/characteristics" + elementFormDefault="qualified"> + <xsd:complexType name="CT_AdditionalCharacteristics"> + <xsd:sequence> + <xsd:element name="characteristic" type="CT_Characteristic" minOccurs="0" + maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Characteristic"> + <xsd:attribute name="name" type="xsd:string" use="required"/> + <xsd:attribute name="relation" type="ST_Relation" use="required"/> + <xsd:attribute name="val" type="xsd:string" use="required"/> + <xsd:attribute name="vocabulary" type="xsd:anyURI" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_Relation"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="ge"/> + <xsd:enumeration value="le"/> + <xsd:enumeration value="gt"/> + <xsd:enumeration value="lt"/> + <xsd:enumeration value="eq"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:element name="additionalCharacteristics" type="CT_AdditionalCharacteristics"/> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd new file mode 100644 index 0000000..ac60252 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd @@ -0,0 +1,144 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" + xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" + elementFormDefault="qualified"> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + schemaLocation="shared-commonSimpleTypes.xsd"/> + <xsd:simpleType name="ST_SourceType"> + <xsd:restriction base="s:ST_String"> + <xsd:enumeration value="ArticleInAPeriodical"/> + <xsd:enumeration value="Book"/> + <xsd:enumeration value="BookSection"/> + <xsd:enumeration value="JournalArticle"/> + <xsd:enumeration value="ConferenceProceedings"/> + <xsd:enumeration value="Report"/> + <xsd:enumeration value="SoundRecording"/> + <xsd:enumeration value="Performance"/> + <xsd:enumeration value="Art"/> + <xsd:enumeration value="DocumentFromInternetSite"/> + <xsd:enumeration value="InternetSite"/> + <xsd:enumeration value="Film"/> + <xsd:enumeration value="Interview"/> + <xsd:enumeration value="Patent"/> + <xsd:enumeration value="ElectronicSource"/> + <xsd:enumeration value="Case"/> + <xsd:enumeration value="Misc"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_NameListType"> + <xsd:sequence> + <xsd:element name="Person" type="CT_PersonType" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PersonType"> + <xsd:sequence> + <xsd:element name="Last" type="s:ST_String" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="First" type="s:ST_String" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="Middle" type="s:ST_String" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_NameType"> + <xsd:sequence> + <xsd:element name="NameList" type="CT_NameListType" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_NameOrCorporateType"> + <xsd:sequence> + <xsd:choice minOccurs="0" maxOccurs="1"> + <xsd:element name="NameList" type="CT_NameListType" minOccurs="1" maxOccurs="1"/> + <xsd:element name="Corporate" minOccurs="1" maxOccurs="1" type="s:ST_String"/> + </xsd:choice> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_AuthorType"> + <xsd:sequence> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="Artist" type="CT_NameType"/> + <xsd:element name="Author" type="CT_NameOrCorporateType"/> + <xsd:element name="BookAuthor" type="CT_NameType"/> + <xsd:element name="Compiler" type="CT_NameType"/> + <xsd:element name="Composer" type="CT_NameType"/> + <xsd:element name="Conductor" type="CT_NameType"/> + <xsd:element name="Counsel" type="CT_NameType"/> + <xsd:element name="Director" type="CT_NameType"/> + <xsd:element name="Editor" type="CT_NameType"/> + <xsd:element name="Interviewee" type="CT_NameType"/> + <xsd:element name="Interviewer" type="CT_NameType"/> + <xsd:element name="Inventor" type="CT_NameType"/> + <xsd:element name="Performer" type="CT_NameOrCorporateType"/> + <xsd:element name="ProducerName" type="CT_NameType"/> + <xsd:element name="Translator" type="CT_NameType"/> + <xsd:element name="Writer" type="CT_NameType"/> + </xsd:choice> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SourceType"> + <xsd:sequence> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="AbbreviatedCaseNumber" type="s:ST_String"/> + <xsd:element name="AlbumTitle" type="s:ST_String"/> + <xsd:element name="Author" type="CT_AuthorType"/> + <xsd:element name="BookTitle" type="s:ST_String"/> + <xsd:element name="Broadcaster" type="s:ST_String"/> + <xsd:element name="BroadcastTitle" type="s:ST_String"/> + <xsd:element name="CaseNumber" type="s:ST_String"/> + <xsd:element name="ChapterNumber" type="s:ST_String"/> + <xsd:element name="City" type="s:ST_String"/> + <xsd:element name="Comments" type="s:ST_String"/> + <xsd:element name="ConferenceName" type="s:ST_String"/> + <xsd:element name="CountryRegion" type="s:ST_String"/> + <xsd:element name="Court" type="s:ST_String"/> + <xsd:element name="Day" type="s:ST_String"/> + <xsd:element name="DayAccessed" type="s:ST_String"/> + <xsd:element name="Department" type="s:ST_String"/> + <xsd:element name="Distributor" type="s:ST_String"/> + <xsd:element name="Edition" type="s:ST_String"/> + <xsd:element name="Guid" type="s:ST_String"/> + <xsd:element name="Institution" type="s:ST_String"/> + <xsd:element name="InternetSiteTitle" type="s:ST_String"/> + <xsd:element name="Issue" type="s:ST_String"/> + <xsd:element name="JournalName" type="s:ST_String"/> + <xsd:element name="LCID" type="s:ST_Lang"/> + <xsd:element name="Medium" type="s:ST_String"/> + <xsd:element name="Month" type="s:ST_String"/> + <xsd:element name="MonthAccessed" type="s:ST_String"/> + <xsd:element name="NumberVolumes" type="s:ST_String"/> + <xsd:element name="Pages" type="s:ST_String"/> + <xsd:element name="PatentNumber" type="s:ST_String"/> + <xsd:element name="PeriodicalTitle" type="s:ST_String"/> + <xsd:element name="ProductionCompany" type="s:ST_String"/> + <xsd:element name="PublicationTitle" type="s:ST_String"/> + <xsd:element name="Publisher" type="s:ST_String"/> + <xsd:element name="RecordingNumber" type="s:ST_String"/> + <xsd:element name="RefOrder" type="s:ST_String"/> + <xsd:element name="Reporter" type="s:ST_String"/> + <xsd:element name="SourceType" type="ST_SourceType"/> + <xsd:element name="ShortTitle" type="s:ST_String"/> + <xsd:element name="StandardNumber" type="s:ST_String"/> + <xsd:element name="StateProvince" type="s:ST_String"/> + <xsd:element name="Station" type="s:ST_String"/> + <xsd:element name="Tag" type="s:ST_String"/> + <xsd:element name="Theater" type="s:ST_String"/> + <xsd:element name="ThesisType" type="s:ST_String"/> + <xsd:element name="Title" type="s:ST_String"/> + <xsd:element name="Type" type="s:ST_String"/> + <xsd:element name="URL" type="s:ST_String"/> + <xsd:element name="Version" type="s:ST_String"/> + <xsd:element name="Volume" type="s:ST_String"/> + <xsd:element name="Year" type="s:ST_String"/> + <xsd:element name="YearAccessed" type="s:ST_String"/> + </xsd:choice> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="Sources" type="CT_Sources"/> + <xsd:complexType name="CT_Sources"> + <xsd:sequence> + <xsd:element name="Source" type="CT_SourceType" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="SelectedStyle" type="s:ST_String"/> + <xsd:attribute name="StyleName" type="s:ST_String"/> + <xsd:attribute name="URI" type="s:ST_String"/> + </xsd:complexType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd new file mode 100644 index 0000000..424b8ba --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd @@ -0,0 +1,174 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + elementFormDefault="qualified"> + <xsd:simpleType name="ST_Lang"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="ST_HexColorRGB"> + <xsd:restriction base="xsd:hexBinary"> + <xsd:length value="3" fixed="true"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Panose"> + <xsd:restriction base="xsd:hexBinary"> + <xsd:length value="10"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_CalendarType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="gregorian"/> + <xsd:enumeration value="gregorianUs"/> + <xsd:enumeration value="gregorianMeFrench"/> + <xsd:enumeration value="gregorianArabic"/> + <xsd:enumeration value="hijri"/> + <xsd:enumeration value="hebrew"/> + <xsd:enumeration value="taiwan"/> + <xsd:enumeration value="japan"/> + <xsd:enumeration value="thai"/> + <xsd:enumeration value="korea"/> + <xsd:enumeration value="saka"/> + <xsd:enumeration value="gregorianXlitEnglish"/> + <xsd:enumeration value="gregorianXlitFrench"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_AlgClass"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="hash"/> + <xsd:enumeration value="custom"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_CryptProv"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="rsaAES"/> + <xsd:enumeration value="rsaFull"/> + <xsd:enumeration value="custom"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_AlgType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="typeAny"/> + <xsd:enumeration value="custom"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ColorType"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="ST_Guid"> + <xsd:restriction base="xsd:token"> + <xsd:pattern value="\{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\}"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_OnOff"> + <xsd:union memberTypes="xsd:boolean ST_OnOff1"/> + </xsd:simpleType> + <xsd:simpleType name="ST_OnOff1"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="on"/> + <xsd:enumeration value="off"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_String"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="ST_XmlName"> + <xsd:restriction base="xsd:NCName"> + <xsd:minLength value="1"/> + <xsd:maxLength value="255"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TrueFalse"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="t"/> + <xsd:enumeration value="f"/> + <xsd:enumeration value="true"/> + <xsd:enumeration value="false"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TrueFalseBlank"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="t"/> + <xsd:enumeration value="f"/> + <xsd:enumeration value="true"/> + <xsd:enumeration value="false"/> + <xsd:enumeration value=""/> + <xsd:enumeration value="True"/> + <xsd:enumeration value="False"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_UnsignedDecimalNumber"> + <xsd:restriction base="xsd:decimal"> + <xsd:minInclusive value="0"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TwipsMeasure"> + <xsd:union memberTypes="ST_UnsignedDecimalNumber ST_PositiveUniversalMeasure"/> + </xsd:simpleType> + <xsd:simpleType name="ST_VerticalAlignRun"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="baseline"/> + <xsd:enumeration value="superscript"/> + <xsd:enumeration value="subscript"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Xstring"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="ST_XAlign"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="left"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="right"/> + <xsd:enumeration value="inside"/> + <xsd:enumeration value="outside"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_YAlign"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="inline"/> + <xsd:enumeration value="top"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="bottom"/> + <xsd:enumeration value="inside"/> + <xsd:enumeration value="outside"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ConformanceClass"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="strict"/> + <xsd:enumeration value="transitional"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_UniversalMeasure"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="-?[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PositiveUniversalMeasure"> + <xsd:restriction base="ST_UniversalMeasure"> + <xsd:pattern value="[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Percentage"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="-?[0-9]+(\.[0-9]+)?%"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FixedPercentage"> + <xsd:restriction base="ST_Percentage"> + <xsd:pattern value="-?((100)|([0-9][0-9]?))(\.[0-9][0-9]?)?%"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PositivePercentage"> + <xsd:restriction base="ST_Percentage"> + <xsd:pattern value="[0-9]+(\.[0-9]+)?%"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PositiveFixedPercentage"> + <xsd:restriction base="ST_Percentage"> + <xsd:pattern value="((100)|([0-9][0-9]?))(\.[0-9][0-9]?)?%"/> + </xsd:restriction> + </xsd:simpleType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd new file mode 100644 index 0000000..2bddce2 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/officeDocument/2006/customXml" + xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/customXml" + elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all"> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + schemaLocation="shared-commonSimpleTypes.xsd"/> + <xsd:complexType name="CT_DatastoreSchemaRef"> + <xsd:attribute name="uri" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_DatastoreSchemaRefs"> + <xsd:sequence> + <xsd:element name="schemaRef" type="CT_DatastoreSchemaRef" minOccurs="0" maxOccurs="unbounded" + /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DatastoreItem"> + <xsd:sequence> + <xsd:element name="schemaRefs" type="CT_DatastoreSchemaRefs" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="itemID" type="s:ST_Guid" use="required"/> + </xsd:complexType> + <xsd:element name="datastoreItem" type="CT_DatastoreItem"/> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd new file mode 100644 index 0000000..8a8c18b --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/schemaLibrary/2006/main" + targetNamespace="http://schemas.openxmlformats.org/schemaLibrary/2006/main" + attributeFormDefault="qualified" elementFormDefault="qualified"> + <xsd:complexType name="CT_Schema"> + <xsd:attribute name="uri" type="xsd:string" default=""/> + <xsd:attribute name="manifestLocation" type="xsd:string"/> + <xsd:attribute name="schemaLocation" type="xsd:string"/> + <xsd:attribute name="schemaLanguage" type="xsd:token"/> + </xsd:complexType> + <xsd:complexType name="CT_SchemaLibrary"> + <xsd:sequence> + <xsd:element name="schema" type="CT_Schema" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="schemaLibrary" type="CT_SchemaLibrary"/> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd new file mode 100644 index 0000000..5c42706 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties" + xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes" + xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties" + blockDefault="#all" elementFormDefault="qualified"> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes" + schemaLocation="shared-documentPropertiesVariantTypes.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + schemaLocation="shared-commonSimpleTypes.xsd"/> + <xsd:element name="Properties" type="CT_Properties"/> + <xsd:complexType name="CT_Properties"> + <xsd:sequence> + <xsd:element name="property" minOccurs="0" maxOccurs="unbounded" type="CT_Property"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Property"> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element ref="vt:vector"/> + <xsd:element ref="vt:array"/> + <xsd:element ref="vt:blob"/> + <xsd:element ref="vt:oblob"/> + <xsd:element ref="vt:empty"/> + <xsd:element ref="vt:null"/> + <xsd:element ref="vt:i1"/> + <xsd:element ref="vt:i2"/> + <xsd:element ref="vt:i4"/> + <xsd:element ref="vt:i8"/> + <xsd:element ref="vt:int"/> + <xsd:element ref="vt:ui1"/> + <xsd:element ref="vt:ui2"/> + <xsd:element ref="vt:ui4"/> + <xsd:element ref="vt:ui8"/> + <xsd:element ref="vt:uint"/> + <xsd:element ref="vt:r4"/> + <xsd:element ref="vt:r8"/> + <xsd:element ref="vt:decimal"/> + <xsd:element ref="vt:lpstr"/> + <xsd:element ref="vt:lpwstr"/> + <xsd:element ref="vt:bstr"/> + <xsd:element ref="vt:date"/> + <xsd:element ref="vt:filetime"/> + <xsd:element ref="vt:bool"/> + <xsd:element ref="vt:cy"/> + <xsd:element ref="vt:error"/> + <xsd:element ref="vt:stream"/> + <xsd:element ref="vt:ostream"/> + <xsd:element ref="vt:storage"/> + <xsd:element ref="vt:ostorage"/> + <xsd:element ref="vt:vstream"/> + <xsd:element ref="vt:clsid"/> + </xsd:choice> + <xsd:attribute name="fmtid" use="required" type="s:ST_Guid"/> + <xsd:attribute name="pid" use="required" type="xsd:int"/> + <xsd:attribute name="name" use="optional" type="xsd:string"/> + <xsd:attribute name="linkTarget" use="optional" type="xsd:string"/> + </xsd:complexType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd new file mode 100644 index 0000000..853c341 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" + xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes" + targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" + elementFormDefault="qualified" blockDefault="#all"> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes" + schemaLocation="shared-documentPropertiesVariantTypes.xsd"/> + <xsd:element name="Properties" type="CT_Properties"/> + <xsd:complexType name="CT_Properties"> + <xsd:all> + <xsd:element name="Template" minOccurs="0" maxOccurs="1" type="xsd:string"/> + <xsd:element name="Manager" minOccurs="0" maxOccurs="1" type="xsd:string"/> + <xsd:element name="Company" minOccurs="0" maxOccurs="1" type="xsd:string"/> + <xsd:element name="Pages" minOccurs="0" maxOccurs="1" type="xsd:int"/> + <xsd:element name="Words" minOccurs="0" maxOccurs="1" type="xsd:int"/> + <xsd:element name="Characters" minOccurs="0" maxOccurs="1" type="xsd:int"/> + <xsd:element name="PresentationFormat" minOccurs="0" maxOccurs="1" type="xsd:string"/> + <xsd:element name="Lines" minOccurs="0" maxOccurs="1" type="xsd:int"/> + <xsd:element name="Paragraphs" minOccurs="0" maxOccurs="1" type="xsd:int"/> + <xsd:element name="Slides" minOccurs="0" maxOccurs="1" type="xsd:int"/> + <xsd:element name="Notes" minOccurs="0" maxOccurs="1" type="xsd:int"/> + <xsd:element name="TotalTime" minOccurs="0" maxOccurs="1" type="xsd:int"/> + <xsd:element name="HiddenSlides" minOccurs="0" maxOccurs="1" type="xsd:int"/> + <xsd:element name="MMClips" minOccurs="0" maxOccurs="1" type="xsd:int"/> + <xsd:element name="ScaleCrop" minOccurs="0" maxOccurs="1" type="xsd:boolean"/> + <xsd:element name="HeadingPairs" minOccurs="0" maxOccurs="1" type="CT_VectorVariant"/> + <xsd:element name="TitlesOfParts" minOccurs="0" maxOccurs="1" type="CT_VectorLpstr"/> + <xsd:element name="LinksUpToDate" minOccurs="0" maxOccurs="1" type="xsd:boolean"/> + <xsd:element name="CharactersWithSpaces" minOccurs="0" maxOccurs="1" type="xsd:int"/> + <xsd:element name="SharedDoc" minOccurs="0" maxOccurs="1" type="xsd:boolean"/> + <xsd:element name="HyperlinkBase" minOccurs="0" maxOccurs="1" type="xsd:string"/> + <xsd:element name="HLinks" minOccurs="0" maxOccurs="1" type="CT_VectorVariant"/> + <xsd:element name="HyperlinksChanged" minOccurs="0" maxOccurs="1" type="xsd:boolean"/> + <xsd:element name="DigSig" minOccurs="0" maxOccurs="1" type="CT_DigSigBlob"/> + <xsd:element name="Application" minOccurs="0" maxOccurs="1" type="xsd:string"/> + <xsd:element name="AppVersion" minOccurs="0" maxOccurs="1" type="xsd:string"/> + <xsd:element name="DocSecurity" minOccurs="0" maxOccurs="1" type="xsd:int"/> + </xsd:all> + </xsd:complexType> + <xsd:complexType name="CT_VectorVariant"> + <xsd:sequence minOccurs="1" maxOccurs="1"> + <xsd:element ref="vt:vector"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_VectorLpstr"> + <xsd:sequence minOccurs="1" maxOccurs="1"> + <xsd:element ref="vt:vector"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DigSigBlob"> + <xsd:sequence minOccurs="1" maxOccurs="1"> + <xsd:element ref="vt:blob"/> + </xsd:sequence> + </xsd:complexType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd new file mode 100644 index 0000000..da835ee --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd @@ -0,0 +1,195 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes" + xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes" + blockDefault="#all" elementFormDefault="qualified"> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + schemaLocation="shared-commonSimpleTypes.xsd"/> + <xsd:simpleType name="ST_VectorBaseType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="variant"/> + <xsd:enumeration value="i1"/> + <xsd:enumeration value="i2"/> + <xsd:enumeration value="i4"/> + <xsd:enumeration value="i8"/> + <xsd:enumeration value="ui1"/> + <xsd:enumeration value="ui2"/> + <xsd:enumeration value="ui4"/> + <xsd:enumeration value="ui8"/> + <xsd:enumeration value="r4"/> + <xsd:enumeration value="r8"/> + <xsd:enumeration value="lpstr"/> + <xsd:enumeration value="lpwstr"/> + <xsd:enumeration value="bstr"/> + <xsd:enumeration value="date"/> + <xsd:enumeration value="filetime"/> + <xsd:enumeration value="bool"/> + <xsd:enumeration value="cy"/> + <xsd:enumeration value="error"/> + <xsd:enumeration value="clsid"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ArrayBaseType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="variant"/> + <xsd:enumeration value="i1"/> + <xsd:enumeration value="i2"/> + <xsd:enumeration value="i4"/> + <xsd:enumeration value="int"/> + <xsd:enumeration value="ui1"/> + <xsd:enumeration value="ui2"/> + <xsd:enumeration value="ui4"/> + <xsd:enumeration value="uint"/> + <xsd:enumeration value="r4"/> + <xsd:enumeration value="r8"/> + <xsd:enumeration value="decimal"/> + <xsd:enumeration value="bstr"/> + <xsd:enumeration value="date"/> + <xsd:enumeration value="bool"/> + <xsd:enumeration value="cy"/> + <xsd:enumeration value="error"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Cy"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="\s*[0-9]*\.[0-9]{4}\s*"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Error"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="\s*0x[0-9A-Za-z]{8}\s*"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Empty"/> + <xsd:complexType name="CT_Null"/> + <xsd:complexType name="CT_Vector"> + <xsd:choice minOccurs="1" maxOccurs="unbounded"> + <xsd:element ref="variant"/> + <xsd:element ref="i1"/> + <xsd:element ref="i2"/> + <xsd:element ref="i4"/> + <xsd:element ref="i8"/> + <xsd:element ref="ui1"/> + <xsd:element ref="ui2"/> + <xsd:element ref="ui4"/> + <xsd:element ref="ui8"/> + <xsd:element ref="r4"/> + <xsd:element ref="r8"/> + <xsd:element ref="lpstr"/> + <xsd:element ref="lpwstr"/> + <xsd:element ref="bstr"/> + <xsd:element ref="date"/> + <xsd:element ref="filetime"/> + <xsd:element ref="bool"/> + <xsd:element ref="cy"/> + <xsd:element ref="error"/> + <xsd:element ref="clsid"/> + </xsd:choice> + <xsd:attribute name="baseType" type="ST_VectorBaseType" use="required"/> + <xsd:attribute name="size" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Array"> + <xsd:choice minOccurs="1" maxOccurs="unbounded"> + <xsd:element ref="variant"/> + <xsd:element ref="i1"/> + <xsd:element ref="i2"/> + <xsd:element ref="i4"/> + <xsd:element ref="int"/> + <xsd:element ref="ui1"/> + <xsd:element ref="ui2"/> + <xsd:element ref="ui4"/> + <xsd:element ref="uint"/> + <xsd:element ref="r4"/> + <xsd:element ref="r8"/> + <xsd:element ref="decimal"/> + <xsd:element ref="bstr"/> + <xsd:element ref="date"/> + <xsd:element ref="bool"/> + <xsd:element ref="error"/> + <xsd:element ref="cy"/> + </xsd:choice> + <xsd:attribute name="lBounds" type="xsd:int" use="required"/> + <xsd:attribute name="uBounds" type="xsd:int" use="required"/> + <xsd:attribute name="baseType" type="ST_ArrayBaseType" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Variant"> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element ref="variant"/> + <xsd:element ref="vector"/> + <xsd:element ref="array"/> + <xsd:element ref="blob"/> + <xsd:element ref="oblob"/> + <xsd:element ref="empty"/> + <xsd:element ref="null"/> + <xsd:element ref="i1"/> + <xsd:element ref="i2"/> + <xsd:element ref="i4"/> + <xsd:element ref="i8"/> + <xsd:element ref="int"/> + <xsd:element ref="ui1"/> + <xsd:element ref="ui2"/> + <xsd:element ref="ui4"/> + <xsd:element ref="ui8"/> + <xsd:element ref="uint"/> + <xsd:element ref="r4"/> + <xsd:element ref="r8"/> + <xsd:element ref="decimal"/> + <xsd:element ref="lpstr"/> + <xsd:element ref="lpwstr"/> + <xsd:element ref="bstr"/> + <xsd:element ref="date"/> + <xsd:element ref="filetime"/> + <xsd:element ref="bool"/> + <xsd:element ref="cy"/> + <xsd:element ref="error"/> + <xsd:element ref="stream"/> + <xsd:element ref="ostream"/> + <xsd:element ref="storage"/> + <xsd:element ref="ostorage"/> + <xsd:element ref="vstream"/> + <xsd:element ref="clsid"/> + </xsd:choice> + </xsd:complexType> + <xsd:complexType name="CT_Vstream"> + <xsd:simpleContent> + <xsd:extension base="xsd:base64Binary"> + <xsd:attribute name="version" type="s:ST_Guid"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + <xsd:element name="variant" type="CT_Variant"/> + <xsd:element name="vector" type="CT_Vector"/> + <xsd:element name="array" type="CT_Array"/> + <xsd:element name="blob" type="xsd:base64Binary"/> + <xsd:element name="oblob" type="xsd:base64Binary"/> + <xsd:element name="empty" type="CT_Empty"/> + <xsd:element name="null" type="CT_Null"/> + <xsd:element name="i1" type="xsd:byte"/> + <xsd:element name="i2" type="xsd:short"/> + <xsd:element name="i4" type="xsd:int"/> + <xsd:element name="i8" type="xsd:long"/> + <xsd:element name="int" type="xsd:int"/> + <xsd:element name="ui1" type="xsd:unsignedByte"/> + <xsd:element name="ui2" type="xsd:unsignedShort"/> + <xsd:element name="ui4" type="xsd:unsignedInt"/> + <xsd:element name="ui8" type="xsd:unsignedLong"/> + <xsd:element name="uint" type="xsd:unsignedInt"/> + <xsd:element name="r4" type="xsd:float"/> + <xsd:element name="r8" type="xsd:double"/> + <xsd:element name="decimal" type="xsd:decimal"/> + <xsd:element name="lpstr" type="xsd:string"/> + <xsd:element name="lpwstr" type="xsd:string"/> + <xsd:element name="bstr" type="xsd:string"/> + <xsd:element name="date" type="xsd:dateTime"/> + <xsd:element name="filetime" type="xsd:dateTime"/> + <xsd:element name="bool" type="xsd:boolean"/> + <xsd:element name="cy" type="ST_Cy"/> + <xsd:element name="error" type="ST_Error"/> + <xsd:element name="stream" type="xsd:base64Binary"/> + <xsd:element name="ostream" type="xsd:base64Binary"/> + <xsd:element name="storage" type="xsd:base64Binary"/> + <xsd:element name="ostorage" type="xsd:base64Binary"/> + <xsd:element name="vstream" type="CT_Vstream"/> + <xsd:element name="clsid" type="s:ST_Guid"/> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd new file mode 100644 index 0000000..87ad265 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd @@ -0,0 +1,582 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/officeDocument/2006/math" + xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" + xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" + xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" + targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/math"> + <xsd:import namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" + schemaLocation="wml.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + schemaLocation="shared-commonSimpleTypes.xsd"/> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd"/> + <xsd:simpleType name="ST_Integer255"> + <xsd:restriction base="xsd:integer"> + <xsd:minInclusive value="1"/> + <xsd:maxInclusive value="255"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Integer255"> + <xsd:attribute name="val" type="ST_Integer255" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_Integer2"> + <xsd:restriction base="xsd:integer"> + <xsd:minInclusive value="-2"/> + <xsd:maxInclusive value="2"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Integer2"> + <xsd:attribute name="val" type="ST_Integer2" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_SpacingRule"> + <xsd:restriction base="xsd:integer"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="4"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SpacingRule"> + <xsd:attribute name="val" type="ST_SpacingRule" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_UnSignedInteger"> + <xsd:restriction base="xsd:unsignedInt"/> + </xsd:simpleType> + <xsd:complexType name="CT_UnSignedInteger"> + <xsd:attribute name="val" type="ST_UnSignedInteger" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_Char"> + <xsd:restriction base="xsd:string"> + <xsd:maxLength value="1"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Char"> + <xsd:attribute name="val" type="ST_Char" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_OnOff"> + <xsd:attribute name="val" type="s:ST_OnOff"/> + </xsd:complexType> + <xsd:complexType name="CT_String"> + <xsd:attribute name="val" type="s:ST_String"/> + </xsd:complexType> + <xsd:complexType name="CT_XAlign"> + <xsd:attribute name="val" type="s:ST_XAlign" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_YAlign"> + <xsd:attribute name="val" type="s:ST_YAlign" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_Shp"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="centered"/> + <xsd:enumeration value="match"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Shp"> + <xsd:attribute name="val" type="ST_Shp" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_FType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="bar"/> + <xsd:enumeration value="skw"/> + <xsd:enumeration value="lin"/> + <xsd:enumeration value="noBar"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_FType"> + <xsd:attribute name="val" type="ST_FType" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_LimLoc"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="undOvr"/> + <xsd:enumeration value="subSup"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_LimLoc"> + <xsd:attribute name="val" type="ST_LimLoc" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_TopBot"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="top"/> + <xsd:enumeration value="bot"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TopBot"> + <xsd:attribute name="val" type="ST_TopBot" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_Script"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="roman"/> + <xsd:enumeration value="script"/> + <xsd:enumeration value="fraktur"/> + <xsd:enumeration value="double-struck"/> + <xsd:enumeration value="sans-serif"/> + <xsd:enumeration value="monospace"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Script"> + <xsd:attribute name="val" type="ST_Script"/> + </xsd:complexType> + <xsd:simpleType name="ST_Style"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="p"/> + <xsd:enumeration value="b"/> + <xsd:enumeration value="i"/> + <xsd:enumeration value="bi"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Style"> + <xsd:attribute name="val" type="ST_Style"/> + </xsd:complexType> + <xsd:complexType name="CT_ManualBreak"> + <xsd:attribute name="alnAt" type="ST_Integer255"/> + </xsd:complexType> + <xsd:group name="EG_ScriptStyle"> + <xsd:sequence> + <xsd:element name="scr" minOccurs="0" type="CT_Script"/> + <xsd:element name="sty" minOccurs="0" type="CT_Style"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_RPR"> + <xsd:sequence> + <xsd:element name="lit" minOccurs="0" type="CT_OnOff"/> + <xsd:choice> + <xsd:element name="nor" minOccurs="0" type="CT_OnOff"/> + <xsd:sequence> + <xsd:group ref="EG_ScriptStyle"/> + </xsd:sequence> + </xsd:choice> + <xsd:element name="brk" minOccurs="0" type="CT_ManualBreak"/> + <xsd:element name="aln" minOccurs="0" type="CT_OnOff"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Text"> + <xsd:simpleContent> + <xsd:extension base="s:ST_String"> + <xsd:attribute ref="xml:space" use="optional"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + <xsd:complexType name="CT_R"> + <xsd:sequence> + <xsd:element name="rPr" type="CT_RPR" minOccurs="0"/> + <xsd:group ref="w:EG_RPr" minOccurs="0"/> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:group ref="w:EG_RunInnerContent"/> + <xsd:element name="t" type="CT_Text" minOccurs="0"/> + </xsd:choice> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CtrlPr"> + <xsd:sequence> + <xsd:group ref="w:EG_RPrMath" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_AccPr"> + <xsd:sequence> + <xsd:element name="chr" type="CT_Char" minOccurs="0"/> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Acc"> + <xsd:sequence> + <xsd:element name="accPr" type="CT_AccPr" minOccurs="0"/> + <xsd:element name="e" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_BarPr"> + <xsd:sequence> + <xsd:element name="pos" type="CT_TopBot" minOccurs="0"/> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Bar"> + <xsd:sequence> + <xsd:element name="barPr" type="CT_BarPr" minOccurs="0"/> + <xsd:element name="e" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_BoxPr"> + <xsd:sequence> + <xsd:element name="opEmu" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="noBreak" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="diff" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="brk" type="CT_ManualBreak" minOccurs="0"/> + <xsd:element name="aln" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Box"> + <xsd:sequence> + <xsd:element name="boxPr" type="CT_BoxPr" minOccurs="0"/> + <xsd:element name="e" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_BorderBoxPr"> + <xsd:sequence> + <xsd:element name="hideTop" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="hideBot" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="hideLeft" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="hideRight" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="strikeH" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="strikeV" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="strikeBLTR" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="strikeTLBR" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_BorderBox"> + <xsd:sequence> + <xsd:element name="borderBoxPr" type="CT_BorderBoxPr" minOccurs="0"/> + <xsd:element name="e" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DPr"> + <xsd:sequence> + <xsd:element name="begChr" type="CT_Char" minOccurs="0"/> + <xsd:element name="sepChr" type="CT_Char" minOccurs="0"/> + <xsd:element name="endChr" type="CT_Char" minOccurs="0"/> + <xsd:element name="grow" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="shp" type="CT_Shp" minOccurs="0"/> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_D"> + <xsd:sequence> + <xsd:element name="dPr" type="CT_DPr" minOccurs="0"/> + <xsd:element name="e" type="CT_OMathArg" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_EqArrPr"> + <xsd:sequence> + <xsd:element name="baseJc" type="CT_YAlign" minOccurs="0"/> + <xsd:element name="maxDist" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="objDist" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="rSpRule" type="CT_SpacingRule" minOccurs="0"/> + <xsd:element name="rSp" type="CT_UnSignedInteger" minOccurs="0"/> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_EqArr"> + <xsd:sequence> + <xsd:element name="eqArrPr" type="CT_EqArrPr" minOccurs="0"/> + <xsd:element name="e" type="CT_OMathArg" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_FPr"> + <xsd:sequence> + <xsd:element name="type" type="CT_FType" minOccurs="0"/> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_F"> + <xsd:sequence> + <xsd:element name="fPr" type="CT_FPr" minOccurs="0"/> + <xsd:element name="num" type="CT_OMathArg"/> + <xsd:element name="den" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_FuncPr"> + <xsd:sequence> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Func"> + <xsd:sequence> + <xsd:element name="funcPr" type="CT_FuncPr" minOccurs="0"/> + <xsd:element name="fName" type="CT_OMathArg"/> + <xsd:element name="e" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GroupChrPr"> + <xsd:sequence> + <xsd:element name="chr" type="CT_Char" minOccurs="0"/> + <xsd:element name="pos" type="CT_TopBot" minOccurs="0"/> + <xsd:element name="vertJc" type="CT_TopBot" minOccurs="0"/> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GroupChr"> + <xsd:sequence> + <xsd:element name="groupChrPr" type="CT_GroupChrPr" minOccurs="0"/> + <xsd:element name="e" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_LimLowPr"> + <xsd:sequence> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_LimLow"> + <xsd:sequence> + <xsd:element name="limLowPr" type="CT_LimLowPr" minOccurs="0"/> + <xsd:element name="e" type="CT_OMathArg"/> + <xsd:element name="lim" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_LimUppPr"> + <xsd:sequence> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_LimUpp"> + <xsd:sequence> + <xsd:element name="limUppPr" type="CT_LimUppPr" minOccurs="0"/> + <xsd:element name="e" type="CT_OMathArg"/> + <xsd:element name="lim" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_MCPr"> + <xsd:sequence> + <xsd:element name="count" type="CT_Integer255" minOccurs="0"/> + <xsd:element name="mcJc" type="CT_XAlign" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_MC"> + <xsd:sequence> + <xsd:element name="mcPr" type="CT_MCPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_MCS"> + <xsd:sequence> + <xsd:element name="mc" type="CT_MC" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_MPr"> + <xsd:sequence> + <xsd:element name="baseJc" type="CT_YAlign" minOccurs="0"/> + <xsd:element name="plcHide" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="rSpRule" type="CT_SpacingRule" minOccurs="0"/> + <xsd:element name="cGpRule" type="CT_SpacingRule" minOccurs="0"/> + <xsd:element name="rSp" type="CT_UnSignedInteger" minOccurs="0"/> + <xsd:element name="cSp" type="CT_UnSignedInteger" minOccurs="0"/> + <xsd:element name="cGp" type="CT_UnSignedInteger" minOccurs="0"/> + <xsd:element name="mcs" type="CT_MCS" minOccurs="0"/> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_MR"> + <xsd:sequence> + <xsd:element name="e" type="CT_OMathArg" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_M"> + <xsd:sequence> + <xsd:element name="mPr" type="CT_MPr" minOccurs="0"/> + <xsd:element name="mr" type="CT_MR" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_NaryPr"> + <xsd:sequence> + <xsd:element name="chr" type="CT_Char" minOccurs="0"/> + <xsd:element name="limLoc" type="CT_LimLoc" minOccurs="0"/> + <xsd:element name="grow" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="subHide" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="supHide" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Nary"> + <xsd:sequence> + <xsd:element name="naryPr" type="CT_NaryPr" minOccurs="0"/> + <xsd:element name="sub" type="CT_OMathArg"/> + <xsd:element name="sup" type="CT_OMathArg"/> + <xsd:element name="e" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PhantPr"> + <xsd:sequence> + <xsd:element name="show" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="zeroWid" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="zeroAsc" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="zeroDesc" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="transp" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Phant"> + <xsd:sequence> + <xsd:element name="phantPr" type="CT_PhantPr" minOccurs="0"/> + <xsd:element name="e" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_RadPr"> + <xsd:sequence> + <xsd:element name="degHide" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Rad"> + <xsd:sequence> + <xsd:element name="radPr" type="CT_RadPr" minOccurs="0"/> + <xsd:element name="deg" type="CT_OMathArg"/> + <xsd:element name="e" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SPrePr"> + <xsd:sequence> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SPre"> + <xsd:sequence> + <xsd:element name="sPrePr" type="CT_SPrePr" minOccurs="0"/> + <xsd:element name="sub" type="CT_OMathArg"/> + <xsd:element name="sup" type="CT_OMathArg"/> + <xsd:element name="e" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SSubPr"> + <xsd:sequence> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SSub"> + <xsd:sequence> + <xsd:element name="sSubPr" type="CT_SSubPr" minOccurs="0"/> + <xsd:element name="e" type="CT_OMathArg"/> + <xsd:element name="sub" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SSubSupPr"> + <xsd:sequence> + <xsd:element name="alnScr" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SSubSup"> + <xsd:sequence> + <xsd:element name="sSubSupPr" type="CT_SSubSupPr" minOccurs="0"/> + <xsd:element name="e" type="CT_OMathArg"/> + <xsd:element name="sub" type="CT_OMathArg"/> + <xsd:element name="sup" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SSupPr"> + <xsd:sequence> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SSup"> + <xsd:sequence> + <xsd:element name="sSupPr" type="CT_SSupPr" minOccurs="0"/> + <xsd:element name="e" type="CT_OMathArg"/> + <xsd:element name="sup" type="CT_OMathArg"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_OMathMathElements"> + <xsd:choice> + <xsd:element name="acc" type="CT_Acc"/> + <xsd:element name="bar" type="CT_Bar"/> + <xsd:element name="box" type="CT_Box"/> + <xsd:element name="borderBox" type="CT_BorderBox"/> + <xsd:element name="d" type="CT_D"/> + <xsd:element name="eqArr" type="CT_EqArr"/> + <xsd:element name="f" type="CT_F"/> + <xsd:element name="func" type="CT_Func"/> + <xsd:element name="groupChr" type="CT_GroupChr"/> + <xsd:element name="limLow" type="CT_LimLow"/> + <xsd:element name="limUpp" type="CT_LimUpp"/> + <xsd:element name="m" type="CT_M"/> + <xsd:element name="nary" type="CT_Nary"/> + <xsd:element name="phant" type="CT_Phant"/> + <xsd:element name="rad" type="CT_Rad"/> + <xsd:element name="sPre" type="CT_SPre"/> + <xsd:element name="sSub" type="CT_SSub"/> + <xsd:element name="sSubSup" type="CT_SSubSup"/> + <xsd:element name="sSup" type="CT_SSup"/> + <xsd:element name="r" type="CT_R"/> + </xsd:choice> + </xsd:group> + <xsd:group name="EG_OMathElements"> + <xsd:choice> + <xsd:group ref="EG_OMathMathElements"/> + <xsd:group ref="w:EG_PContentMath"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_OMathArgPr"> + <xsd:sequence> + <xsd:element name="argSz" type="CT_Integer2" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_OMathArg"> + <xsd:sequence> + <xsd:element name="argPr" type="CT_OMathArgPr" minOccurs="0"/> + <xsd:group ref="EG_OMathElements" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_Jc"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="left"/> + <xsd:enumeration value="right"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="centerGroup"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_OMathJc"> + <xsd:attribute name="val" type="ST_Jc"/> + </xsd:complexType> + <xsd:complexType name="CT_OMathParaPr"> + <xsd:sequence> + <xsd:element name="jc" type="CT_OMathJc" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TwipsMeasure"> + <xsd:attribute name="val" type="s:ST_TwipsMeasure" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_BreakBin"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="before"/> + <xsd:enumeration value="after"/> + <xsd:enumeration value="repeat"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_BreakBin"> + <xsd:attribute name="val" type="ST_BreakBin"/> + </xsd:complexType> + <xsd:simpleType name="ST_BreakBinSub"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="--"/> + <xsd:enumeration value="-+"/> + <xsd:enumeration value="+-"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_BreakBinSub"> + <xsd:attribute name="val" type="ST_BreakBinSub"/> + </xsd:complexType> + <xsd:complexType name="CT_MathPr"> + <xsd:sequence> + <xsd:element name="mathFont" type="CT_String" minOccurs="0"/> + <xsd:element name="brkBin" type="CT_BreakBin" minOccurs="0"/> + <xsd:element name="brkBinSub" type="CT_BreakBinSub" minOccurs="0"/> + <xsd:element name="smallFrac" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="dispDef" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="lMargin" type="CT_TwipsMeasure" minOccurs="0"/> + <xsd:element name="rMargin" type="CT_TwipsMeasure" minOccurs="0"/> + <xsd:element name="defJc" type="CT_OMathJc" minOccurs="0"/> + <xsd:element name="preSp" type="CT_TwipsMeasure" minOccurs="0"/> + <xsd:element name="postSp" type="CT_TwipsMeasure" minOccurs="0"/> + <xsd:element name="interSp" type="CT_TwipsMeasure" minOccurs="0"/> + <xsd:element name="intraSp" type="CT_TwipsMeasure" minOccurs="0"/> + <xsd:choice minOccurs="0"> + <xsd:element name="wrapIndent" type="CT_TwipsMeasure"/> + <xsd:element name="wrapRight" type="CT_OnOff"/> + </xsd:choice> + <xsd:element name="intLim" type="CT_LimLoc" minOccurs="0"/> + <xsd:element name="naryLim" type="CT_LimLoc" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="mathPr" type="CT_MathPr"/> + <xsd:complexType name="CT_OMathPara"> + <xsd:sequence> + <xsd:element name="oMathParaPr" type="CT_OMathParaPr" minOccurs="0"/> + <xsd:element name="oMath" type="CT_OMath" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_OMath"> + <xsd:sequence> + <xsd:group ref="EG_OMathElements" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="oMathPara" type="CT_OMathPara"/> + <xsd:element name="oMath" type="CT_OMath"/> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd new file mode 100644 index 0000000..9e86f1b --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + elementFormDefault="qualified" + targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + blockDefault="#all"> + <xsd:simpleType name="ST_RelationshipId"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:attribute name="id" type="ST_RelationshipId"/> + <xsd:attribute name="embed" type="ST_RelationshipId"/> + <xsd:attribute name="link" type="ST_RelationshipId"/> + <xsd:attribute name="dm" type="ST_RelationshipId" default=""/> + <xsd:attribute name="lo" type="ST_RelationshipId" default=""/> + <xsd:attribute name="qs" type="ST_RelationshipId" default=""/> + <xsd:attribute name="cs" type="ST_RelationshipId" default=""/> + <xsd:attribute name="blip" type="ST_RelationshipId" default=""/> + <xsd:attribute name="pict" type="ST_RelationshipId"/> + <xsd:attribute name="href" type="ST_RelationshipId"/> + <xsd:attribute name="topLeft" type="ST_RelationshipId"/> + <xsd:attribute name="topRight" type="ST_RelationshipId"/> + <xsd:attribute name="bottomLeft" type="ST_RelationshipId"/> + <xsd:attribute name="bottomRight" type="ST_RelationshipId"/> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd new file mode 100644 index 0000000..d0be42e --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd @@ -0,0 +1,4439 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" + xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" + xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + targetNamespace="http://schemas.openxmlformats.org/spreadsheetml/2006/main" + elementFormDefault="qualified"> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + schemaLocation="shared-relationshipReference.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + schemaLocation="shared-commonSimpleTypes.xsd"/> + <xsd:import + namespace="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" + schemaLocation="dml-spreadsheetDrawing.xsd"/> + <xsd:complexType name="CT_AutoFilter"> + <xsd:sequence> + <xsd:element name="filterColumn" minOccurs="0" maxOccurs="unbounded" type="CT_FilterColumn"/> + <xsd:element name="sortState" minOccurs="0" maxOccurs="1" type="CT_SortState"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="ref" type="ST_Ref"/> + </xsd:complexType> + <xsd:complexType name="CT_FilterColumn"> + <xsd:choice minOccurs="0" maxOccurs="1"> + <xsd:element name="filters" type="CT_Filters" minOccurs="0" maxOccurs="1"/> + <xsd:element name="top10" type="CT_Top10" minOccurs="0" maxOccurs="1"/> + <xsd:element name="customFilters" type="CT_CustomFilters" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dynamicFilter" type="CT_DynamicFilter" minOccurs="0" maxOccurs="1"/> + <xsd:element name="colorFilter" type="CT_ColorFilter" minOccurs="0" maxOccurs="1"/> + <xsd:element name="iconFilter" minOccurs="0" maxOccurs="1" type="CT_IconFilter"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:choice> + <xsd:attribute name="colId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="hiddenButton" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showButton" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_Filters"> + <xsd:sequence> + <xsd:element name="filter" type="CT_Filter" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="dateGroupItem" type="CT_DateGroupItem" minOccurs="0" maxOccurs="unbounded" + /> + </xsd:sequence> + <xsd:attribute name="blank" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="calendarType" type="s:ST_CalendarType" use="optional" default="none"/> + </xsd:complexType> + <xsd:complexType name="CT_Filter"> + <xsd:attribute name="val" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomFilters"> + <xsd:sequence> + <xsd:element name="customFilter" type="CT_CustomFilter" minOccurs="1" maxOccurs="2"/> + </xsd:sequence> + <xsd:attribute name="and" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomFilter"> + <xsd:attribute name="operator" type="ST_FilterOperator" default="equal" use="optional"/> + <xsd:attribute name="val" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:complexType name="CT_Top10"> + <xsd:attribute name="top" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="percent" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="val" type="xsd:double" use="required"/> + <xsd:attribute name="filterVal" type="xsd:double" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_ColorFilter"> + <xsd:attribute name="dxfId" type="ST_DxfId" use="optional"/> + <xsd:attribute name="cellColor" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_IconFilter"> + <xsd:attribute name="iconSet" type="ST_IconSetType" use="required"/> + <xsd:attribute name="iconId" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_FilterOperator"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="equal"/> + <xsd:enumeration value="lessThan"/> + <xsd:enumeration value="lessThanOrEqual"/> + <xsd:enumeration value="notEqual"/> + <xsd:enumeration value="greaterThanOrEqual"/> + <xsd:enumeration value="greaterThan"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_DynamicFilter"> + <xsd:attribute name="type" type="ST_DynamicFilterType" use="required"/> + <xsd:attribute name="val" type="xsd:double" use="optional"/> + <xsd:attribute name="valIso" type="xsd:dateTime" use="optional"/> + <xsd:attribute name="maxVal" type="xsd:double" use="optional"/> + <xsd:attribute name="maxValIso" type="xsd:dateTime" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_DynamicFilterType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="null"/> + <xsd:enumeration value="aboveAverage"/> + <xsd:enumeration value="belowAverage"/> + <xsd:enumeration value="tomorrow"/> + <xsd:enumeration value="today"/> + <xsd:enumeration value="yesterday"/> + <xsd:enumeration value="nextWeek"/> + <xsd:enumeration value="thisWeek"/> + <xsd:enumeration value="lastWeek"/> + <xsd:enumeration value="nextMonth"/> + <xsd:enumeration value="thisMonth"/> + <xsd:enumeration value="lastMonth"/> + <xsd:enumeration value="nextQuarter"/> + <xsd:enumeration value="thisQuarter"/> + <xsd:enumeration value="lastQuarter"/> + <xsd:enumeration value="nextYear"/> + <xsd:enumeration value="thisYear"/> + <xsd:enumeration value="lastYear"/> + <xsd:enumeration value="yearToDate"/> + <xsd:enumeration value="Q1"/> + <xsd:enumeration value="Q2"/> + <xsd:enumeration value="Q3"/> + <xsd:enumeration value="Q4"/> + <xsd:enumeration value="M1"/> + <xsd:enumeration value="M2"/> + <xsd:enumeration value="M3"/> + <xsd:enumeration value="M4"/> + <xsd:enumeration value="M5"/> + <xsd:enumeration value="M6"/> + <xsd:enumeration value="M7"/> + <xsd:enumeration value="M8"/> + <xsd:enumeration value="M9"/> + <xsd:enumeration value="M10"/> + <xsd:enumeration value="M11"/> + <xsd:enumeration value="M12"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_IconSetType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="3Arrows"/> + <xsd:enumeration value="3ArrowsGray"/> + <xsd:enumeration value="3Flags"/> + <xsd:enumeration value="3TrafficLights1"/> + <xsd:enumeration value="3TrafficLights2"/> + <xsd:enumeration value="3Signs"/> + <xsd:enumeration value="3Symbols"/> + <xsd:enumeration value="3Symbols2"/> + <xsd:enumeration value="4Arrows"/> + <xsd:enumeration value="4ArrowsGray"/> + <xsd:enumeration value="4RedToBlack"/> + <xsd:enumeration value="4Rating"/> + <xsd:enumeration value="4TrafficLights"/> + <xsd:enumeration value="5Arrows"/> + <xsd:enumeration value="5ArrowsGray"/> + <xsd:enumeration value="5Rating"/> + <xsd:enumeration value="5Quarters"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SortState"> + <xsd:sequence> + <xsd:element name="sortCondition" minOccurs="0" maxOccurs="64" type="CT_SortCondition"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="columnSort" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="caseSensitive" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="sortMethod" type="ST_SortMethod" use="optional" default="none"/> + <xsd:attribute name="ref" type="ST_Ref" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SortCondition"> + <xsd:attribute name="descending" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="sortBy" type="ST_SortBy" use="optional" default="value"/> + <xsd:attribute name="ref" type="ST_Ref" use="required"/> + <xsd:attribute name="customList" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="dxfId" type="ST_DxfId" use="optional"/> + <xsd:attribute name="iconSet" type="ST_IconSetType" use="optional" default="3Arrows"/> + <xsd:attribute name="iconId" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_SortBy"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="value"/> + <xsd:enumeration value="cellColor"/> + <xsd:enumeration value="fontColor"/> + <xsd:enumeration value="icon"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_SortMethod"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="stroke"/> + <xsd:enumeration value="pinYin"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_DateGroupItem"> + <xsd:attribute name="year" type="xsd:unsignedShort" use="required"/> + <xsd:attribute name="month" type="xsd:unsignedShort" use="optional"/> + <xsd:attribute name="day" type="xsd:unsignedShort" use="optional"/> + <xsd:attribute name="hour" type="xsd:unsignedShort" use="optional"/> + <xsd:attribute name="minute" type="xsd:unsignedShort" use="optional"/> + <xsd:attribute name="second" type="xsd:unsignedShort" use="optional"/> + <xsd:attribute name="dateTimeGrouping" type="ST_DateTimeGrouping" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_DateTimeGrouping"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="year"/> + <xsd:enumeration value="month"/> + <xsd:enumeration value="day"/> + <xsd:enumeration value="hour"/> + <xsd:enumeration value="minute"/> + <xsd:enumeration value="second"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_CellRef"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="ST_Ref"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="ST_RefA"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="ST_Sqref"> + <xsd:list itemType="ST_Ref"/> + </xsd:simpleType> + <xsd:simpleType name="ST_Formula"> + <xsd:restriction base="s:ST_Xstring"/> + </xsd:simpleType> + <xsd:simpleType name="ST_UnsignedIntHex"> + <xsd:restriction base="xsd:hexBinary"> + <xsd:length value="4"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_UnsignedShortHex"> + <xsd:restriction base="xsd:hexBinary"> + <xsd:length value="2"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_XStringElement"> + <xsd:attribute name="v" type="s:ST_Xstring" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Extension"> + <xsd:sequence> + <xsd:any processContents="lax"/> + </xsd:sequence> + <xsd:attribute name="uri" type="xsd:token"/> + </xsd:complexType> + <xsd:complexType name="CT_ObjectAnchor"> + <xsd:sequence> + <xsd:element ref="xdr:from" minOccurs="1" maxOccurs="1"/> + <xsd:element ref="xdr:to" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="moveWithCells" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="sizeWithCells" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:group name="EG_ExtensionList"> + <xsd:sequence> + <xsd:element name="ext" type="CT_Extension" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_ExtensionList"> + <xsd:sequence> + <xsd:group ref="EG_ExtensionList" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="calcChain" type="CT_CalcChain"/> + <xsd:complexType name="CT_CalcChain"> + <xsd:sequence> + <xsd:element name="c" type="CT_CalcCell" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CalcCell"> + <xsd:attribute name="r" type="ST_CellRef" use="optional"/> + <xsd:attribute name="ref" type="ST_CellRef" use="optional"/> + <xsd:attribute name="i" type="xsd:int" use="optional" default="0"/> + <xsd:attribute name="s" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="l" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="t" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="a" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:element name="comments" type="CT_Comments"/> + <xsd:complexType name="CT_Comments"> + <xsd:sequence> + <xsd:element name="authors" type="CT_Authors" minOccurs="1" maxOccurs="1"/> + <xsd:element name="commentList" type="CT_CommentList" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Authors"> + <xsd:sequence> + <xsd:element name="author" type="s:ST_Xstring" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CommentList"> + <xsd:sequence> + <xsd:element name="comment" type="CT_Comment" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Comment"> + <xsd:sequence> + <xsd:element name="text" type="CT_Rst" minOccurs="1" maxOccurs="1"/> + <xsd:element name="commentPr" type="CT_CommentPr" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="ref" type="ST_Ref" use="required"/> + <xsd:attribute name="authorId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="guid" type="s:ST_Guid" use="optional"/> + <xsd:attribute name="shapeId" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_CommentPr"> + <xsd:sequence> + <xsd:element name="anchor" type="CT_ObjectAnchor" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="locked" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="defaultSize" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="print" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="disabled" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="autoFill" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="autoLine" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="altText" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="textHAlign" type="ST_TextHAlign" use="optional" default="left"/> + <xsd:attribute name="textVAlign" type="ST_TextVAlign" use="optional" default="top"/> + <xsd:attribute name="lockText" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="justLastX" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="autoScale" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:simpleType name="ST_TextHAlign"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="left"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="right"/> + <xsd:enumeration value="justify"/> + <xsd:enumeration value="distributed"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextVAlign"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="top"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="bottom"/> + <xsd:enumeration value="justify"/> + <xsd:enumeration value="distributed"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:element name="MapInfo" type="CT_MapInfo"/> + <xsd:complexType name="CT_MapInfo"> + <xsd:sequence> + <xsd:element name="Schema" type="CT_Schema" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="Map" type="CT_Map" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="SelectionNamespaces" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Schema" mixed="true"> + <xsd:sequence> + <xsd:any/> + </xsd:sequence> + <xsd:attribute name="ID" type="xsd:string" use="required"/> + <xsd:attribute name="SchemaRef" type="xsd:string" use="optional"/> + <xsd:attribute name="Namespace" type="xsd:string" use="optional"/> + <xsd:attribute name="SchemaLanguage" type="xsd:token" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Map"> + <xsd:sequence> + <xsd:element name="DataBinding" type="CT_DataBinding" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="ID" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="Name" type="xsd:string" use="required"/> + <xsd:attribute name="RootElement" type="xsd:string" use="required"/> + <xsd:attribute name="SchemaID" type="xsd:string" use="required"/> + <xsd:attribute name="ShowImportExportValidationErrors" type="xsd:boolean" use="required"/> + <xsd:attribute name="AutoFit" type="xsd:boolean" use="required"/> + <xsd:attribute name="Append" type="xsd:boolean" use="required"/> + <xsd:attribute name="PreserveSortAFLayout" type="xsd:boolean" use="required"/> + <xsd:attribute name="PreserveFormat" type="xsd:boolean" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_DataBinding"> + <xsd:sequence> + <xsd:any/> + </xsd:sequence> + <xsd:attribute name="DataBindingName" type="xsd:string" use="optional"/> + <xsd:attribute name="FileBinding" type="xsd:boolean" use="optional"/> + <xsd:attribute name="ConnectionID" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="FileBindingName" type="xsd:string" use="optional"/> + <xsd:attribute name="DataBindingLoadMode" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:element name="connections" type="CT_Connections"/> + <xsd:complexType name="CT_Connections"> + <xsd:sequence> + <xsd:element name="connection" minOccurs="1" maxOccurs="unbounded" type="CT_Connection"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Connection"> + <xsd:sequence> + <xsd:element name="dbPr" minOccurs="0" maxOccurs="1" type="CT_DbPr"/> + <xsd:element name="olapPr" minOccurs="0" maxOccurs="1" type="CT_OlapPr"/> + <xsd:element name="webPr" minOccurs="0" maxOccurs="1" type="CT_WebPr"/> + <xsd:element name="textPr" minOccurs="0" maxOccurs="1" type="CT_TextPr"/> + <xsd:element name="parameters" minOccurs="0" maxOccurs="1" type="CT_Parameters"/> + <xsd:element name="extLst" minOccurs="0" maxOccurs="1" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="id" use="required" type="xsd:unsignedInt"/> + <xsd:attribute name="sourceFile" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="odcFile" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="keepAlive" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="interval" use="optional" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="name" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="description" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="type" use="optional" type="xsd:unsignedInt"/> + <xsd:attribute name="reconnectionMethod" use="optional" type="xsd:unsignedInt" default="1"/> + <xsd:attribute name="refreshedVersion" use="required" type="xsd:unsignedByte"/> + <xsd:attribute name="minRefreshableVersion" use="optional" type="xsd:unsignedByte" default="0"/> + <xsd:attribute name="savePassword" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="new" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="deleted" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="onlyUseConnectionFile" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="background" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="refreshOnLoad" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="saveData" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="credentials" use="optional" type="ST_CredMethod" default="integrated"/> + <xsd:attribute name="singleSignOnId" use="optional" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:simpleType name="ST_CredMethod"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="integrated"/> + <xsd:enumeration value="none"/> + <xsd:enumeration value="stored"/> + <xsd:enumeration value="prompt"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_DbPr"> + <xsd:attribute name="connection" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="command" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="serverCommand" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="commandType" use="optional" type="xsd:unsignedInt" default="2"/> + </xsd:complexType> + <xsd:complexType name="CT_OlapPr"> + <xsd:attribute name="local" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="localConnection" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="localRefresh" use="optional" type="xsd:boolean" default="true"/> + <xsd:attribute name="sendLocale" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="rowDrillCount" use="optional" type="xsd:unsignedInt"/> + <xsd:attribute name="serverFill" use="optional" type="xsd:boolean" default="true"/> + <xsd:attribute name="serverNumberFormat" use="optional" type="xsd:boolean" default="true"/> + <xsd:attribute name="serverFont" use="optional" type="xsd:boolean" default="true"/> + <xsd:attribute name="serverFontColor" use="optional" type="xsd:boolean" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_WebPr"> + <xsd:sequence> + <xsd:element name="tables" minOccurs="0" maxOccurs="1" type="CT_Tables"/> + </xsd:sequence> + <xsd:attribute name="xml" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="sourceData" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="parsePre" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="consecutive" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="firstRow" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="xl97" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="textDates" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="xl2000" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="url" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="post" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="htmlTables" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="htmlFormat" use="optional" type="ST_HtmlFmt" default="none"/> + <xsd:attribute name="editPage" use="optional" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:simpleType name="ST_HtmlFmt"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="rtf"/> + <xsd:enumeration value="all"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Parameters"> + <xsd:sequence> + <xsd:element name="parameter" minOccurs="1" maxOccurs="unbounded" type="CT_Parameter"/> + </xsd:sequence> + <xsd:attribute name="count" use="optional" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_Parameter"> + <xsd:attribute name="name" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="sqlType" use="optional" type="xsd:int" default="0"/> + <xsd:attribute name="parameterType" use="optional" type="ST_ParameterType" default="prompt"/> + <xsd:attribute name="refreshOnChange" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="prompt" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="boolean" use="optional" type="xsd:boolean"/> + <xsd:attribute name="double" use="optional" type="xsd:double"/> + <xsd:attribute name="integer" use="optional" type="xsd:int"/> + <xsd:attribute name="string" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="cell" use="optional" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:simpleType name="ST_ParameterType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="prompt"/> + <xsd:enumeration value="value"/> + <xsd:enumeration value="cell"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Tables"> + <xsd:choice minOccurs="1" maxOccurs="unbounded"> + <xsd:element name="m" type="CT_TableMissing"/> + <xsd:element name="s" type="CT_XStringElement"/> + <xsd:element name="x" type="CT_Index"/> + </xsd:choice> + <xsd:attribute name="count" use="optional" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_TableMissing"/> + <xsd:complexType name="CT_TextPr"> + <xsd:sequence> + <xsd:element name="textFields" minOccurs="0" maxOccurs="1" type="CT_TextFields"/> + </xsd:sequence> + <xsd:attribute name="prompt" use="optional" type="xsd:boolean" default="true"/> + <xsd:attribute name="fileType" use="optional" type="ST_FileType" default="win"/> + <xsd:attribute name="codePage" use="optional" type="xsd:unsignedInt" default="1252"/> + <xsd:attribute name="characterSet" use="optional" type="xsd:string"/> + <xsd:attribute name="firstRow" use="optional" type="xsd:unsignedInt" default="1"/> + <xsd:attribute name="sourceFile" use="optional" type="s:ST_Xstring" default=""/> + <xsd:attribute name="delimited" use="optional" type="xsd:boolean" default="true"/> + <xsd:attribute name="decimal" use="optional" type="s:ST_Xstring" default="."/> + <xsd:attribute name="thousands" use="optional" type="s:ST_Xstring" default=","/> + <xsd:attribute name="tab" use="optional" type="xsd:boolean" default="true"/> + <xsd:attribute name="space" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="comma" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="semicolon" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="consecutive" use="optional" type="xsd:boolean" default="false"/> + <xsd:attribute name="qualifier" use="optional" type="ST_Qualifier" default="doubleQuote"/> + <xsd:attribute name="delimiter" use="optional" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:simpleType name="ST_FileType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="mac"/> + <xsd:enumeration value="win"/> + <xsd:enumeration value="dos"/> + <xsd:enumeration value="lin"/> + <xsd:enumeration value="other"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Qualifier"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="doubleQuote"/> + <xsd:enumeration value="singleQuote"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextFields"> + <xsd:sequence> + <xsd:element name="textField" minOccurs="1" maxOccurs="unbounded" type="CT_TextField"/> + </xsd:sequence> + <xsd:attribute name="count" use="optional" type="xsd:unsignedInt" default="1"/> + </xsd:complexType> + <xsd:complexType name="CT_TextField"> + <xsd:attribute name="type" use="optional" type="ST_ExternalConnectionType" default="general"/> + <xsd:attribute name="position" use="optional" type="xsd:unsignedInt" default="0"/> + </xsd:complexType> + <xsd:simpleType name="ST_ExternalConnectionType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="general"/> + <xsd:enumeration value="text"/> + <xsd:enumeration value="MDY"/> + <xsd:enumeration value="DMY"/> + <xsd:enumeration value="YMD"/> + <xsd:enumeration value="MYD"/> + <xsd:enumeration value="DYM"/> + <xsd:enumeration value="YDM"/> + <xsd:enumeration value="skip"/> + <xsd:enumeration value="EMD"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:element name="pivotCacheDefinition" type="CT_PivotCacheDefinition"/> + <xsd:element name="pivotCacheRecords" type="CT_PivotCacheRecords"/> + <xsd:element name="pivotTableDefinition" type="CT_pivotTableDefinition"/> + <xsd:complexType name="CT_PivotCacheDefinition"> + <xsd:sequence> + <xsd:element name="cacheSource" type="CT_CacheSource" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cacheFields" type="CT_CacheFields" minOccurs="1" maxOccurs="1"/> + <xsd:element name="cacheHierarchies" minOccurs="0" type="CT_CacheHierarchies"/> + <xsd:element name="kpis" minOccurs="0" type="CT_PCDKPIs"/> + <xsd:element name="tupleCache" minOccurs="0" type="CT_TupleCache"/> + <xsd:element name="calculatedItems" minOccurs="0" type="CT_CalculatedItems"/> + <xsd:element name="calculatedMembers" type="CT_CalculatedMembers" minOccurs="0"/> + <xsd:element name="dimensions" type="CT_Dimensions" minOccurs="0"/> + <xsd:element name="measureGroups" type="CT_MeasureGroups" minOccurs="0"/> + <xsd:element name="maps" type="CT_MeasureDimensionMaps" minOccurs="0"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute ref="r:id" use="optional"/> + <xsd:attribute name="invalid" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="saveData" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="refreshOnLoad" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="optimizeMemory" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="enableRefresh" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="refreshedBy" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="refreshedDate" type="xsd:double" use="optional"/> + <xsd:attribute name="refreshedDateIso" type="xsd:dateTime" use="optional"/> + <xsd:attribute name="backgroundQuery" type="xsd:boolean" default="false"/> + <xsd:attribute name="missingItemsLimit" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="createdVersion" type="xsd:unsignedByte" use="optional" default="0"/> + <xsd:attribute name="refreshedVersion" type="xsd:unsignedByte" use="optional" default="0"/> + <xsd:attribute name="minRefreshableVersion" type="xsd:unsignedByte" use="optional" default="0"/> + <xsd:attribute name="recordCount" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="upgradeOnRefresh" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="tupleCache" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="supportSubquery" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="supportAdvancedDrill" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_CacheFields"> + <xsd:sequence> + <xsd:element name="cacheField" type="CT_CacheField" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_CacheField"> + <xsd:sequence> + <xsd:element name="sharedItems" type="CT_SharedItems" minOccurs="0" maxOccurs="1"/> + <xsd:element name="fieldGroup" minOccurs="0" type="CT_FieldGroup"/> + <xsd:element name="mpMap" minOccurs="0" maxOccurs="unbounded" type="CT_X"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="caption" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="propertyName" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="serverField" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="uniqueList" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="numFmtId" type="ST_NumFmtId" use="optional"/> + <xsd:attribute name="formula" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="sqlType" type="xsd:int" use="optional" default="0"/> + <xsd:attribute name="hierarchy" type="xsd:int" use="optional" default="0"/> + <xsd:attribute name="level" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="databaseField" type="xsd:boolean" default="true"/> + <xsd:attribute name="mappingCount" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="memberPropertyField" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_CacheSource"> + <xsd:choice minOccurs="0" maxOccurs="1"> + <xsd:element name="worksheetSource" type="CT_WorksheetSource" minOccurs="1" maxOccurs="1"/> + <xsd:element name="consolidation" type="CT_Consolidation" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0"/> + </xsd:choice> + <xsd:attribute name="type" type="ST_SourceType" use="required"/> + <xsd:attribute name="connectionId" type="xsd:unsignedInt" default="0" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_SourceType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="worksheet"/> + <xsd:enumeration value="external"/> + <xsd:enumeration value="consolidation"/> + <xsd:enumeration value="scenario"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_WorksheetSource"> + <xsd:attribute name="ref" type="ST_Ref" use="optional"/> + <xsd:attribute name="name" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="sheet" type="s:ST_Xstring" use="optional"/> + <xsd:attribute ref="r:id" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Consolidation"> + <xsd:sequence> + <xsd:element name="pages" type="CT_Pages" minOccurs="0" maxOccurs="1"/> + <xsd:element name="rangeSets" type="CT_RangeSets" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="autoPage" type="xsd:boolean" default="true" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Pages"> + <xsd:sequence> + <xsd:element name="page" type="CT_PCDSCPage" minOccurs="1" maxOccurs="4"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_PCDSCPage"> + <xsd:sequence> + <xsd:element name="pageItem" type="CT_PageItem" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_PageItem"> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_RangeSets"> + <xsd:sequence> + <xsd:element name="rangeSet" type="CT_RangeSet" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_RangeSet"> + <xsd:attribute name="i1" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="i2" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="i3" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="i4" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="ref" type="ST_Ref" use="optional"/> + <xsd:attribute name="name" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="sheet" type="s:ST_Xstring" use="optional"/> + <xsd:attribute ref="r:id" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_SharedItems"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="m" type="CT_Missing" minOccurs="1" maxOccurs="1"/> + <xsd:element name="n" type="CT_Number" minOccurs="1" maxOccurs="1"/> + <xsd:element name="b" type="CT_Boolean" minOccurs="1" maxOccurs="1"/> + <xsd:element name="e" type="CT_Error" minOccurs="1" maxOccurs="1"/> + <xsd:element name="s" type="CT_String" minOccurs="1" maxOccurs="1"/> + <xsd:element name="d" type="CT_DateTime" minOccurs="1" maxOccurs="1"/> + </xsd:choice> + <xsd:attribute name="containsSemiMixedTypes" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="containsNonDate" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="containsDate" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="containsString" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="containsBlank" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="containsMixedTypes" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="containsNumber" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="containsInteger" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="minValue" type="xsd:double" use="optional"/> + <xsd:attribute name="maxValue" type="xsd:double" use="optional"/> + <xsd:attribute name="minDate" type="xsd:dateTime" use="optional"/> + <xsd:attribute name="maxDate" type="xsd:dateTime" use="optional"/> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="longText" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_Missing"> + <xsd:sequence> + <xsd:element name="tpls" minOccurs="0" maxOccurs="unbounded" type="CT_Tuples"/> + <xsd:element name="x" minOccurs="0" maxOccurs="unbounded" type="CT_X"/> + </xsd:sequence> + <xsd:attribute name="u" type="xsd:boolean"/> + <xsd:attribute name="f" type="xsd:boolean"/> + <xsd:attribute name="c" type="s:ST_Xstring"/> + <xsd:attribute name="cp" type="xsd:unsignedInt"/> + <xsd:attribute name="in" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="bc" type="ST_UnsignedIntHex" use="optional"/> + <xsd:attribute name="fc" type="ST_UnsignedIntHex" use="optional"/> + <xsd:attribute name="i" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="un" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="st" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="b" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_Number"> + <xsd:sequence> + <xsd:element name="tpls" minOccurs="0" maxOccurs="unbounded" type="CT_Tuples"/> + <xsd:element name="x" minOccurs="0" maxOccurs="unbounded" type="CT_X"/> + </xsd:sequence> + <xsd:attribute name="v" use="required" type="xsd:double"/> + <xsd:attribute name="u" type="xsd:boolean"/> + <xsd:attribute name="f" type="xsd:boolean"/> + <xsd:attribute name="c" type="s:ST_Xstring"/> + <xsd:attribute name="cp" type="xsd:unsignedInt"/> + <xsd:attribute name="in" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="bc" type="ST_UnsignedIntHex" use="optional"/> + <xsd:attribute name="fc" type="ST_UnsignedIntHex" use="optional"/> + <xsd:attribute name="i" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="un" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="st" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="b" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_Boolean"> + <xsd:sequence> + <xsd:element name="x" minOccurs="0" maxOccurs="unbounded" type="CT_X"/> + </xsd:sequence> + <xsd:attribute name="v" use="required" type="xsd:boolean"/> + <xsd:attribute name="u" type="xsd:boolean"/> + <xsd:attribute name="f" type="xsd:boolean"/> + <xsd:attribute name="c" type="s:ST_Xstring"/> + <xsd:attribute name="cp" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_Error"> + <xsd:sequence> + <xsd:element name="tpls" minOccurs="0" type="CT_Tuples"/> + <xsd:element name="x" minOccurs="0" maxOccurs="unbounded" type="CT_X"/> + </xsd:sequence> + <xsd:attribute name="v" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="u" type="xsd:boolean"/> + <xsd:attribute name="f" type="xsd:boolean"/> + <xsd:attribute name="c" type="s:ST_Xstring"/> + <xsd:attribute name="cp" type="xsd:unsignedInt"/> + <xsd:attribute name="in" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="bc" type="ST_UnsignedIntHex" use="optional"/> + <xsd:attribute name="fc" type="ST_UnsignedIntHex" use="optional"/> + <xsd:attribute name="i" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="un" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="st" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="b" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_String"> + <xsd:sequence> + <xsd:element name="tpls" minOccurs="0" maxOccurs="unbounded" type="CT_Tuples"/> + <xsd:element name="x" minOccurs="0" maxOccurs="unbounded" type="CT_X"/> + </xsd:sequence> + <xsd:attribute name="v" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="u" type="xsd:boolean"/> + <xsd:attribute name="f" type="xsd:boolean"/> + <xsd:attribute name="c" type="s:ST_Xstring"/> + <xsd:attribute name="cp" type="xsd:unsignedInt"/> + <xsd:attribute name="in" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="bc" type="ST_UnsignedIntHex" use="optional"/> + <xsd:attribute name="fc" type="ST_UnsignedIntHex" use="optional"/> + <xsd:attribute name="i" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="un" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="st" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="b" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_DateTime"> + <xsd:sequence> + <xsd:element name="x" minOccurs="0" maxOccurs="unbounded" type="CT_X"/> + </xsd:sequence> + <xsd:attribute name="v" use="required" type="xsd:dateTime"/> + <xsd:attribute name="u" type="xsd:boolean"/> + <xsd:attribute name="f" type="xsd:boolean"/> + <xsd:attribute name="c" type="s:ST_Xstring"/> + <xsd:attribute name="cp" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_FieldGroup"> + <xsd:sequence> + <xsd:element name="rangePr" minOccurs="0" type="CT_RangePr"/> + <xsd:element name="discretePr" minOccurs="0" type="CT_DiscretePr"/> + <xsd:element name="groupItems" minOccurs="0" type="CT_GroupItems"/> + </xsd:sequence> + <xsd:attribute name="par" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="base" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_RangePr"> + <xsd:attribute name="autoStart" type="xsd:boolean" default="true"/> + <xsd:attribute name="autoEnd" type="xsd:boolean" default="true"/> + <xsd:attribute name="groupBy" type="ST_GroupBy" default="range"/> + <xsd:attribute name="startNum" type="xsd:double"/> + <xsd:attribute name="endNum" type="xsd:double"/> + <xsd:attribute name="startDate" type="xsd:dateTime"/> + <xsd:attribute name="endDate" type="xsd:dateTime"/> + <xsd:attribute name="groupInterval" type="xsd:double" default="1"/> + </xsd:complexType> + <xsd:simpleType name="ST_GroupBy"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="range"/> + <xsd:enumeration value="seconds"/> + <xsd:enumeration value="minutes"/> + <xsd:enumeration value="hours"/> + <xsd:enumeration value="days"/> + <xsd:enumeration value="months"/> + <xsd:enumeration value="quarters"/> + <xsd:enumeration value="years"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_DiscretePr"> + <xsd:sequence> + <xsd:element name="x" maxOccurs="unbounded" type="CT_Index"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_GroupItems"> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="m" type="CT_Missing"/> + <xsd:element name="n" type="CT_Number"/> + <xsd:element name="b" type="CT_Boolean"/> + <xsd:element name="e" type="CT_Error"/> + <xsd:element name="s" type="CT_String"/> + <xsd:element name="d" type="CT_DateTime"/> + </xsd:choice> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_PivotCacheRecords"> + <xsd:sequence> + <xsd:element name="r" minOccurs="0" maxOccurs="unbounded" type="CT_Record"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_Record"> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="m" type="CT_Missing"/> + <xsd:element name="n" type="CT_Number"/> + <xsd:element name="b" type="CT_Boolean"/> + <xsd:element name="e" type="CT_Error"/> + <xsd:element name="s" type="CT_String"/> + <xsd:element name="d" type="CT_DateTime"/> + <xsd:element name="x" type="CT_Index"/> + </xsd:choice> + </xsd:complexType> + <xsd:complexType name="CT_PCDKPIs"> + <xsd:sequence> + <xsd:element name="kpi" minOccurs="0" maxOccurs="unbounded" type="CT_PCDKPI"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_PCDKPI"> + <xsd:attribute name="uniqueName" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="caption" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="displayFolder" type="s:ST_Xstring"/> + <xsd:attribute name="measureGroup" type="s:ST_Xstring"/> + <xsd:attribute name="parent" type="s:ST_Xstring"/> + <xsd:attribute name="value" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="goal" type="s:ST_Xstring"/> + <xsd:attribute name="status" type="s:ST_Xstring"/> + <xsd:attribute name="trend" type="s:ST_Xstring"/> + <xsd:attribute name="weight" type="s:ST_Xstring"/> + <xsd:attribute name="time" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:complexType name="CT_CacheHierarchies"> + <xsd:sequence> + <xsd:element name="cacheHierarchy" minOccurs="0" maxOccurs="unbounded" + type="CT_CacheHierarchy"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_CacheHierarchy"> + <xsd:sequence> + <xsd:element name="fieldsUsage" minOccurs="0" type="CT_FieldsUsage"/> + <xsd:element name="groupLevels" minOccurs="0" type="CT_GroupLevels"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="uniqueName" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="caption" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="measure" type="xsd:boolean" default="false"/> + <xsd:attribute name="set" type="xsd:boolean" default="false"/> + <xsd:attribute name="parentSet" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="iconSet" type="xsd:int" default="0"/> + <xsd:attribute name="attribute" type="xsd:boolean" default="false"/> + <xsd:attribute name="time" type="xsd:boolean" default="false"/> + <xsd:attribute name="keyAttribute" type="xsd:boolean" default="false"/> + <xsd:attribute name="defaultMemberUniqueName" type="s:ST_Xstring"/> + <xsd:attribute name="allUniqueName" type="s:ST_Xstring"/> + <xsd:attribute name="allCaption" type="s:ST_Xstring"/> + <xsd:attribute name="dimensionUniqueName" type="s:ST_Xstring"/> + <xsd:attribute name="displayFolder" type="s:ST_Xstring"/> + <xsd:attribute name="measureGroup" type="s:ST_Xstring"/> + <xsd:attribute name="measures" type="xsd:boolean" default="false"/> + <xsd:attribute name="count" use="required" type="xsd:unsignedInt"/> + <xsd:attribute name="oneField" type="xsd:boolean" default="false"/> + <xsd:attribute name="memberValueDatatype" use="optional" type="xsd:unsignedShort"/> + <xsd:attribute name="unbalanced" use="optional" type="xsd:boolean"/> + <xsd:attribute name="unbalancedGroup" use="optional" type="xsd:boolean"/> + <xsd:attribute name="hidden" type="xsd:boolean" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_FieldsUsage"> + <xsd:sequence> + <xsd:element name="fieldUsage" minOccurs="0" maxOccurs="unbounded" type="CT_FieldUsage"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_FieldUsage"> + <xsd:attribute name="x" use="required" type="xsd:int"/> + </xsd:complexType> + <xsd:complexType name="CT_GroupLevels"> + <xsd:sequence> + <xsd:element name="groupLevel" maxOccurs="unbounded" type="CT_GroupLevel"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_GroupLevel"> + <xsd:sequence> + <xsd:element name="groups" minOccurs="0" type="CT_Groups"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="uniqueName" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="caption" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="user" type="xsd:boolean" default="false"/> + <xsd:attribute name="customRollUp" type="xsd:boolean" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_Groups"> + <xsd:sequence> + <xsd:element name="group" maxOccurs="unbounded" type="CT_LevelGroup"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_LevelGroup"> + <xsd:sequence> + <xsd:element name="groupMembers" type="CT_GroupMembers"/> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="uniqueName" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="caption" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="uniqueParent" type="s:ST_Xstring"/> + <xsd:attribute name="id" type="xsd:int"/> + </xsd:complexType> + <xsd:complexType name="CT_GroupMembers"> + <xsd:sequence> + <xsd:element name="groupMember" maxOccurs="unbounded" type="CT_GroupMember"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_GroupMember"> + <xsd:attribute name="uniqueName" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="group" type="xsd:boolean" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_TupleCache"> + <xsd:sequence> + <xsd:element name="entries" minOccurs="0" type="CT_PCDSDTCEntries"/> + <xsd:element name="sets" minOccurs="0" type="CT_Sets"/> + <xsd:element name="queryCache" minOccurs="0" type="CT_QueryCache"/> + <xsd:element name="serverFormats" minOccurs="0" maxOccurs="1" type="CT_ServerFormats"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ServerFormat"> + <xsd:attribute name="culture" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="format" use="optional" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:complexType name="CT_ServerFormats"> + <xsd:sequence> + <xsd:element name="serverFormat" type="CT_ServerFormat" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_PCDSDTCEntries"> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="m" type="CT_Missing"/> + <xsd:element name="n" type="CT_Number"/> + <xsd:element name="e" type="CT_Error"/> + <xsd:element name="s" type="CT_String"/> + </xsd:choice> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_Tuples"> + <xsd:sequence> + <xsd:element name="tpl" type="CT_Tuple" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="c" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Tuple"> + <xsd:attribute name="fld" type="xsd:unsignedInt"/> + <xsd:attribute name="hier" type="xsd:unsignedInt"/> + <xsd:attribute name="item" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Sets"> + <xsd:sequence> + <xsd:element name="set" maxOccurs="unbounded" type="CT_Set"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_Set"> + <xsd:sequence> + <xsd:element name="tpls" minOccurs="0" maxOccurs="unbounded" type="CT_Tuples"/> + <xsd:element name="sortByTuple" minOccurs="0" type="CT_Tuples"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + <xsd:attribute name="maxRank" use="required" type="xsd:int"/> + <xsd:attribute name="setDefinition" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="sortType" type="ST_SortType" default="none"/> + <xsd:attribute name="queryFailed" type="xsd:boolean" default="false"/> + </xsd:complexType> + <xsd:simpleType name="ST_SortType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="ascending"/> + <xsd:enumeration value="descending"/> + <xsd:enumeration value="ascendingAlpha"/> + <xsd:enumeration value="descendingAlpha"/> + <xsd:enumeration value="ascendingNatural"/> + <xsd:enumeration value="descendingNatural"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_QueryCache"> + <xsd:sequence> + <xsd:element name="query" maxOccurs="unbounded" type="CT_Query"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_Query"> + <xsd:sequence> + <xsd:element name="tpls" minOccurs="0" type="CT_Tuples"/> + </xsd:sequence> + <xsd:attribute name="mdx" use="required" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:complexType name="CT_CalculatedItems"> + <xsd:sequence> + <xsd:element name="calculatedItem" maxOccurs="unbounded" type="CT_CalculatedItem"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_CalculatedItem"> + <xsd:sequence> + <xsd:element name="pivotArea" type="CT_PivotArea"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="field" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="formula" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:complexType name="CT_CalculatedMembers"> + <xsd:sequence> + <xsd:element name="calculatedMember" maxOccurs="unbounded" type="CT_CalculatedMember"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_CalculatedMember"> + <xsd:sequence minOccurs="0"> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="mdx" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="memberName" type="s:ST_Xstring"/> + <xsd:attribute name="hierarchy" type="s:ST_Xstring"/> + <xsd:attribute name="parent" type="s:ST_Xstring"/> + <xsd:attribute name="solveOrder" type="xsd:int" default="0"/> + <xsd:attribute name="set" type="xsd:boolean" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_pivotTableDefinition"> + <xsd:sequence> + <xsd:element name="location" type="CT_Location"/> + <xsd:element name="pivotFields" type="CT_PivotFields" minOccurs="0"/> + <xsd:element name="rowFields" type="CT_RowFields" minOccurs="0"/> + <xsd:element name="rowItems" type="CT_rowItems" minOccurs="0"/> + <xsd:element name="colFields" type="CT_ColFields" minOccurs="0"/> + <xsd:element name="colItems" type="CT_colItems" minOccurs="0"/> + <xsd:element name="pageFields" type="CT_PageFields" minOccurs="0"/> + <xsd:element name="dataFields" type="CT_DataFields" minOccurs="0"/> + <xsd:element name="formats" type="CT_Formats" minOccurs="0"/> + <xsd:element name="conditionalFormats" type="CT_ConditionalFormats" minOccurs="0"/> + <xsd:element name="chartFormats" type="CT_ChartFormats" minOccurs="0"/> + <xsd:element name="pivotHierarchies" type="CT_PivotHierarchies" minOccurs="0"/> + <xsd:element name="pivotTableStyleInfo" minOccurs="0" maxOccurs="1" type="CT_PivotTableStyle"/> + <xsd:element name="filters" minOccurs="0" maxOccurs="1" type="CT_PivotFilters"/> + <xsd:element name="rowHierarchiesUsage" type="CT_RowHierarchiesUsage" minOccurs="0" + maxOccurs="1"/> + <xsd:element name="colHierarchiesUsage" type="CT_ColHierarchiesUsage" minOccurs="0" + maxOccurs="1"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="cacheId" use="required" type="xsd:unsignedInt"/> + <xsd:attribute name="dataOnRows" type="xsd:boolean" default="false"/> + <xsd:attribute name="dataPosition" type="xsd:unsignedInt" use="optional"/> + <xsd:attributeGroup ref="AG_AutoFormat"/> + <xsd:attribute name="dataCaption" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="grandTotalCaption" type="s:ST_Xstring"/> + <xsd:attribute name="errorCaption" type="s:ST_Xstring"/> + <xsd:attribute name="showError" type="xsd:boolean" default="false"/> + <xsd:attribute name="missingCaption" type="s:ST_Xstring"/> + <xsd:attribute name="showMissing" type="xsd:boolean" default="true"/> + <xsd:attribute name="pageStyle" type="s:ST_Xstring"/> + <xsd:attribute name="pivotTableStyle" type="s:ST_Xstring"/> + <xsd:attribute name="vacatedStyle" type="s:ST_Xstring"/> + <xsd:attribute name="tag" type="s:ST_Xstring"/> + <xsd:attribute name="updatedVersion" type="xsd:unsignedByte" default="0"/> + <xsd:attribute name="minRefreshableVersion" type="xsd:unsignedByte" default="0"/> + <xsd:attribute name="asteriskTotals" type="xsd:boolean" default="false"/> + <xsd:attribute name="showItems" type="xsd:boolean" default="true"/> + <xsd:attribute name="editData" type="xsd:boolean" default="false"/> + <xsd:attribute name="disableFieldList" type="xsd:boolean" default="false"/> + <xsd:attribute name="showCalcMbrs" type="xsd:boolean" default="true"/> + <xsd:attribute name="visualTotals" type="xsd:boolean" default="true"/> + <xsd:attribute name="showMultipleLabel" type="xsd:boolean" default="true"/> + <xsd:attribute name="showDataDropDown" type="xsd:boolean" default="true"/> + <xsd:attribute name="showDrill" type="xsd:boolean" default="true"/> + <xsd:attribute name="printDrill" type="xsd:boolean" default="false"/> + <xsd:attribute name="showMemberPropertyTips" type="xsd:boolean" default="true"/> + <xsd:attribute name="showDataTips" type="xsd:boolean" default="true"/> + <xsd:attribute name="enableWizard" type="xsd:boolean" default="true"/> + <xsd:attribute name="enableDrill" type="xsd:boolean" default="true"/> + <xsd:attribute name="enableFieldProperties" type="xsd:boolean" default="true"/> + <xsd:attribute name="preserveFormatting" type="xsd:boolean" default="true"/> + <xsd:attribute name="useAutoFormatting" type="xsd:boolean" default="false"/> + <xsd:attribute name="pageWrap" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="pageOverThenDown" type="xsd:boolean" default="false"/> + <xsd:attribute name="subtotalHiddenItems" type="xsd:boolean" default="false"/> + <xsd:attribute name="rowGrandTotals" type="xsd:boolean" default="true"/> + <xsd:attribute name="colGrandTotals" type="xsd:boolean" default="true"/> + <xsd:attribute name="fieldPrintTitles" type="xsd:boolean" default="false"/> + <xsd:attribute name="itemPrintTitles" type="xsd:boolean" default="false"/> + <xsd:attribute name="mergeItem" type="xsd:boolean" default="false"/> + <xsd:attribute name="showDropZones" type="xsd:boolean" default="true"/> + <xsd:attribute name="createdVersion" type="xsd:unsignedByte" default="0"/> + <xsd:attribute name="indent" type="xsd:unsignedInt" default="1"/> + <xsd:attribute name="showEmptyRow" type="xsd:boolean" default="false"/> + <xsd:attribute name="showEmptyCol" type="xsd:boolean" default="false"/> + <xsd:attribute name="showHeaders" type="xsd:boolean" default="true"/> + <xsd:attribute name="compact" type="xsd:boolean" default="true"/> + <xsd:attribute name="outline" type="xsd:boolean" default="false"/> + <xsd:attribute name="outlineData" type="xsd:boolean" default="false"/> + <xsd:attribute name="compactData" type="xsd:boolean" default="true"/> + <xsd:attribute name="published" type="xsd:boolean" default="false"/> + <xsd:attribute name="gridDropZones" type="xsd:boolean" default="false"/> + <xsd:attribute name="immersive" type="xsd:boolean" default="true"/> + <xsd:attribute name="multipleFieldFilters" type="xsd:boolean" default="true"/> + <xsd:attribute name="chartFormat" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="rowHeaderCaption" type="s:ST_Xstring"/> + <xsd:attribute name="colHeaderCaption" type="s:ST_Xstring"/> + <xsd:attribute name="fieldListSortAscending" type="xsd:boolean" default="false"/> + <xsd:attribute name="mdxSubqueries" type="xsd:boolean" default="false"/> + <xsd:attribute name="customListSort" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_Location"> + <xsd:attribute name="ref" use="required" type="ST_Ref"/> + <xsd:attribute name="firstHeaderRow" use="required" type="xsd:unsignedInt"/> + <xsd:attribute name="firstDataRow" use="required" type="xsd:unsignedInt"/> + <xsd:attribute name="firstDataCol" use="required" type="xsd:unsignedInt"/> + <xsd:attribute name="rowPageCount" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="colPageCount" type="xsd:unsignedInt" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_PivotFields"> + <xsd:sequence> + <xsd:element name="pivotField" maxOccurs="unbounded" type="CT_PivotField"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_PivotField"> + <xsd:sequence> + <xsd:element name="items" minOccurs="0" type="CT_Items"/> + <xsd:element name="autoSortScope" minOccurs="0" type="CT_AutoSortScope"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="name" type="s:ST_Xstring"/> + <xsd:attribute name="axis" use="optional" type="ST_Axis"/> + <xsd:attribute name="dataField" type="xsd:boolean" default="false"/> + <xsd:attribute name="subtotalCaption" type="s:ST_Xstring"/> + <xsd:attribute name="showDropDowns" type="xsd:boolean" default="true"/> + <xsd:attribute name="hiddenLevel" type="xsd:boolean" default="false"/> + <xsd:attribute name="uniqueMemberProperty" type="s:ST_Xstring"/> + <xsd:attribute name="compact" type="xsd:boolean" default="true"/> + <xsd:attribute name="allDrilled" type="xsd:boolean" default="false"/> + <xsd:attribute name="numFmtId" type="ST_NumFmtId" use="optional"/> + <xsd:attribute name="outline" type="xsd:boolean" default="true"/> + <xsd:attribute name="subtotalTop" type="xsd:boolean" default="true"/> + <xsd:attribute name="dragToRow" type="xsd:boolean" default="true"/> + <xsd:attribute name="dragToCol" type="xsd:boolean" default="true"/> + <xsd:attribute name="multipleItemSelectionAllowed" type="xsd:boolean" default="false"/> + <xsd:attribute name="dragToPage" type="xsd:boolean" default="true"/> + <xsd:attribute name="dragToData" type="xsd:boolean" default="true"/> + <xsd:attribute name="dragOff" type="xsd:boolean" default="true"/> + <xsd:attribute name="showAll" type="xsd:boolean" default="true"/> + <xsd:attribute name="insertBlankRow" type="xsd:boolean" default="false"/> + <xsd:attribute name="serverField" type="xsd:boolean" default="false"/> + <xsd:attribute name="insertPageBreak" type="xsd:boolean" default="false"/> + <xsd:attribute name="autoShow" type="xsd:boolean" default="false"/> + <xsd:attribute name="topAutoShow" type="xsd:boolean" default="true"/> + <xsd:attribute name="hideNewItems" type="xsd:boolean" default="false"/> + <xsd:attribute name="measureFilter" type="xsd:boolean" default="false"/> + <xsd:attribute name="includeNewItemsInFilter" type="xsd:boolean" default="false"/> + <xsd:attribute name="itemPageCount" type="xsd:unsignedInt" default="10"/> + <xsd:attribute name="sortType" type="ST_FieldSortType" default="manual"/> + <xsd:attribute name="dataSourceSort" type="xsd:boolean" use="optional"/> + <xsd:attribute name="nonAutoSortDefault" type="xsd:boolean" default="false"/> + <xsd:attribute name="rankBy" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="defaultSubtotal" type="xsd:boolean" default="true"/> + <xsd:attribute name="sumSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="countASubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="avgSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="maxSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="minSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="productSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="countSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="stdDevSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="stdDevPSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="varSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="varPSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="showPropCell" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showPropTip" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showPropAsCaption" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="defaultAttributeDrillState" type="xsd:boolean" use="optional" + default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_AutoSortScope"> + <xsd:sequence> + <xsd:element name="pivotArea" type="CT_PivotArea"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Items"> + <xsd:sequence> + <xsd:element name="item" maxOccurs="unbounded" type="CT_Item"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_Item"> + <xsd:attribute name="n" type="s:ST_Xstring"/> + <xsd:attribute name="t" type="ST_ItemType" default="data"/> + <xsd:attribute name="h" type="xsd:boolean" default="false"/> + <xsd:attribute name="s" type="xsd:boolean" default="false"/> + <xsd:attribute name="sd" type="xsd:boolean" default="true"/> + <xsd:attribute name="f" type="xsd:boolean" default="false"/> + <xsd:attribute name="m" type="xsd:boolean" default="false"/> + <xsd:attribute name="c" type="xsd:boolean" default="false"/> + <xsd:attribute name="x" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="d" type="xsd:boolean" default="false"/> + <xsd:attribute name="e" type="xsd:boolean" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_PageFields"> + <xsd:sequence> + <xsd:element name="pageField" maxOccurs="unbounded" type="CT_PageField"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_PageField"> + <xsd:sequence minOccurs="0"> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="fld" use="required" type="xsd:int"/> + <xsd:attribute name="item" use="optional" type="xsd:unsignedInt"/> + <xsd:attribute name="hier" type="xsd:int"/> + <xsd:attribute name="name" type="s:ST_Xstring"/> + <xsd:attribute name="cap" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:complexType name="CT_DataFields"> + <xsd:sequence> + <xsd:element name="dataField" maxOccurs="unbounded" type="CT_DataField"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_DataField"> + <xsd:sequence> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="name" use="optional" type="s:ST_Xstring"/> + <xsd:attribute name="fld" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="subtotal" type="ST_DataConsolidateFunction" default="sum"/> + <xsd:attribute name="showDataAs" type="ST_ShowDataAs" default="normal"/> + <xsd:attribute name="baseField" type="xsd:int" default="-1"/> + <xsd:attribute name="baseItem" type="xsd:unsignedInt" default="1048832"/> + <xsd:attribute name="numFmtId" type="ST_NumFmtId" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_rowItems"> + <xsd:sequence> + <xsd:element name="i" maxOccurs="unbounded" type="CT_I"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_colItems"> + <xsd:sequence> + <xsd:element name="i" maxOccurs="unbounded" type="CT_I"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_I"> + <xsd:sequence> + <xsd:element name="x" minOccurs="0" maxOccurs="unbounded" type="CT_X"/> + </xsd:sequence> + <xsd:attribute name="t" type="ST_ItemType" default="data"/> + <xsd:attribute name="r" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="i" type="xsd:unsignedInt" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_X"> + <xsd:attribute name="v" type="xsd:int" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_RowFields"> + <xsd:sequence> + <xsd:element name="field" maxOccurs="unbounded" type="CT_Field"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_ColFields"> + <xsd:sequence> + <xsd:element name="field" maxOccurs="unbounded" type="CT_Field"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_Field"> + <xsd:attribute name="x" type="xsd:int" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Formats"> + <xsd:sequence> + <xsd:element name="format" maxOccurs="unbounded" type="CT_Format"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_Format"> + <xsd:sequence> + <xsd:element name="pivotArea" type="CT_PivotArea"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="action" type="ST_FormatAction" default="formatting"/> + <xsd:attribute name="dxfId" type="ST_DxfId" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_ConditionalFormats"> + <xsd:sequence> + <xsd:element name="conditionalFormat" maxOccurs="unbounded" type="CT_ConditionalFormat"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_ConditionalFormat"> + <xsd:sequence> + <xsd:element name="pivotAreas" type="CT_PivotAreas"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="scope" type="ST_Scope" default="selection"/> + <xsd:attribute name="type" type="ST_Type" default="none"/> + <xsd:attribute name="priority" use="required" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_PivotAreas"> + <xsd:sequence> + <xsd:element name="pivotArea" minOccurs="0" maxOccurs="unbounded" type="CT_PivotArea"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:simpleType name="ST_Scope"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="selection"/> + <xsd:enumeration value="data"/> + <xsd:enumeration value="field"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Type"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="all"/> + <xsd:enumeration value="row"/> + <xsd:enumeration value="column"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_ChartFormats"> + <xsd:sequence> + <xsd:element name="chartFormat" maxOccurs="unbounded" type="CT_ChartFormat"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_ChartFormat"> + <xsd:sequence> + <xsd:element name="pivotArea" type="CT_PivotArea"/> + </xsd:sequence> + <xsd:attribute name="chart" use="required" type="xsd:unsignedInt"/> + <xsd:attribute name="format" use="required" type="xsd:unsignedInt"/> + <xsd:attribute name="series" type="xsd:boolean" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_PivotHierarchies"> + <xsd:sequence> + <xsd:element name="pivotHierarchy" maxOccurs="unbounded" type="CT_PivotHierarchy"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_PivotHierarchy"> + <xsd:sequence> + <xsd:element name="mps" minOccurs="0" type="CT_MemberProperties"/> + <xsd:element name="members" minOccurs="0" maxOccurs="unbounded" type="CT_Members"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="outline" type="xsd:boolean" default="false"/> + <xsd:attribute name="multipleItemSelectionAllowed" type="xsd:boolean" default="false"/> + <xsd:attribute name="subtotalTop" type="xsd:boolean" default="false"/> + <xsd:attribute name="showInFieldList" type="xsd:boolean" default="true"/> + <xsd:attribute name="dragToRow" type="xsd:boolean" default="true"/> + <xsd:attribute name="dragToCol" type="xsd:boolean" default="true"/> + <xsd:attribute name="dragToPage" type="xsd:boolean" default="true"/> + <xsd:attribute name="dragToData" type="xsd:boolean" default="false"/> + <xsd:attribute name="dragOff" type="xsd:boolean" default="true"/> + <xsd:attribute name="includeNewItemsInFilter" type="xsd:boolean" default="false"/> + <xsd:attribute name="caption" type="s:ST_Xstring" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_RowHierarchiesUsage"> + <xsd:sequence> + <xsd:element name="rowHierarchyUsage" minOccurs="1" maxOccurs="unbounded" + type="CT_HierarchyUsage"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_ColHierarchiesUsage"> + <xsd:sequence> + <xsd:element name="colHierarchyUsage" minOccurs="1" maxOccurs="unbounded" + type="CT_HierarchyUsage"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_HierarchyUsage"> + <xsd:attribute name="hierarchyUsage" type="xsd:int" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_MemberProperties"> + <xsd:sequence> + <xsd:element name="mp" maxOccurs="unbounded" type="CT_MemberProperty"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_MemberProperty"> + <xsd:attribute name="name" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="showCell" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showTip" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showAsCaption" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="nameLen" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="pPos" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="pLen" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="level" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="field" use="required" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_Members"> + <xsd:sequence> + <xsd:element name="member" maxOccurs="unbounded" type="CT_Member"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + <xsd:attribute name="level" use="optional" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_Member"> + <xsd:attribute name="name" use="required" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:complexType name="CT_Dimensions"> + <xsd:sequence> + <xsd:element name="dimension" minOccurs="0" maxOccurs="unbounded" type="CT_PivotDimension"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_PivotDimension"> + <xsd:attribute name="measure" type="xsd:boolean" default="false"/> + <xsd:attribute name="name" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="uniqueName" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="caption" use="required" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:complexType name="CT_MeasureGroups"> + <xsd:sequence> + <xsd:element name="measureGroup" minOccurs="0" maxOccurs="unbounded" type="CT_MeasureGroup"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_MeasureDimensionMaps"> + <xsd:sequence> + <xsd:element name="map" minOccurs="0" maxOccurs="unbounded" type="CT_MeasureDimensionMap"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_MeasureGroup"> + <xsd:attribute name="name" use="required" type="s:ST_Xstring"/> + <xsd:attribute name="caption" use="required" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:complexType name="CT_MeasureDimensionMap"> + <xsd:attribute name="measureGroup" use="optional" type="xsd:unsignedInt"/> + <xsd:attribute name="dimension" use="optional" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_PivotTableStyle"> + <xsd:attribute name="name" type="xsd:string"/> + <xsd:attribute name="showRowHeaders" type="xsd:boolean"/> + <xsd:attribute name="showColHeaders" type="xsd:boolean"/> + <xsd:attribute name="showRowStripes" type="xsd:boolean"/> + <xsd:attribute name="showColStripes" type="xsd:boolean"/> + <xsd:attribute name="showLastColumn" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_PivotFilters"> + <xsd:sequence> + <xsd:element name="filter" minOccurs="0" maxOccurs="unbounded" type="CT_PivotFilter"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_PivotFilter"> + <xsd:sequence> + <xsd:element name="autoFilter" minOccurs="1" maxOccurs="1" type="CT_AutoFilter"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="fld" use="required" type="xsd:unsignedInt"/> + <xsd:attribute name="mpFld" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="type" use="required" type="ST_PivotFilterType"/> + <xsd:attribute name="evalOrder" use="optional" type="xsd:int" default="0"/> + <xsd:attribute name="id" use="required" type="xsd:unsignedInt"/> + <xsd:attribute name="iMeasureHier" use="optional" type="xsd:unsignedInt"/> + <xsd:attribute name="iMeasureFld" use="optional" type="xsd:unsignedInt"/> + <xsd:attribute name="name" type="s:ST_Xstring"/> + <xsd:attribute name="description" type="s:ST_Xstring"/> + <xsd:attribute name="stringValue1" type="s:ST_Xstring"/> + <xsd:attribute name="stringValue2" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:simpleType name="ST_ShowDataAs"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="normal"/> + <xsd:enumeration value="difference"/> + <xsd:enumeration value="percent"/> + <xsd:enumeration value="percentDiff"/> + <xsd:enumeration value="runTotal"/> + <xsd:enumeration value="percentOfRow"/> + <xsd:enumeration value="percentOfCol"/> + <xsd:enumeration value="percentOfTotal"/> + <xsd:enumeration value="index"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ItemType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="data"/> + <xsd:enumeration value="default"/> + <xsd:enumeration value="sum"/> + <xsd:enumeration value="countA"/> + <xsd:enumeration value="avg"/> + <xsd:enumeration value="max"/> + <xsd:enumeration value="min"/> + <xsd:enumeration value="product"/> + <xsd:enumeration value="count"/> + <xsd:enumeration value="stdDev"/> + <xsd:enumeration value="stdDevP"/> + <xsd:enumeration value="var"/> + <xsd:enumeration value="varP"/> + <xsd:enumeration value="grand"/> + <xsd:enumeration value="blank"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FormatAction"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="blank"/> + <xsd:enumeration value="formatting"/> + <xsd:enumeration value="drill"/> + <xsd:enumeration value="formula"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FieldSortType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="manual"/> + <xsd:enumeration value="ascending"/> + <xsd:enumeration value="descending"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PivotFilterType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="unknown"/> + <xsd:enumeration value="count"/> + <xsd:enumeration value="percent"/> + <xsd:enumeration value="sum"/> + <xsd:enumeration value="captionEqual"/> + <xsd:enumeration value="captionNotEqual"/> + <xsd:enumeration value="captionBeginsWith"/> + <xsd:enumeration value="captionNotBeginsWith"/> + <xsd:enumeration value="captionEndsWith"/> + <xsd:enumeration value="captionNotEndsWith"/> + <xsd:enumeration value="captionContains"/> + <xsd:enumeration value="captionNotContains"/> + <xsd:enumeration value="captionGreaterThan"/> + <xsd:enumeration value="captionGreaterThanOrEqual"/> + <xsd:enumeration value="captionLessThan"/> + <xsd:enumeration value="captionLessThanOrEqual"/> + <xsd:enumeration value="captionBetween"/> + <xsd:enumeration value="captionNotBetween"/> + <xsd:enumeration value="valueEqual"/> + <xsd:enumeration value="valueNotEqual"/> + <xsd:enumeration value="valueGreaterThan"/> + <xsd:enumeration value="valueGreaterThanOrEqual"/> + <xsd:enumeration value="valueLessThan"/> + <xsd:enumeration value="valueLessThanOrEqual"/> + <xsd:enumeration value="valueBetween"/> + <xsd:enumeration value="valueNotBetween"/> + <xsd:enumeration value="dateEqual"/> + <xsd:enumeration value="dateNotEqual"/> + <xsd:enumeration value="dateOlderThan"/> + <xsd:enumeration value="dateOlderThanOrEqual"/> + <xsd:enumeration value="dateNewerThan"/> + <xsd:enumeration value="dateNewerThanOrEqual"/> + <xsd:enumeration value="dateBetween"/> + <xsd:enumeration value="dateNotBetween"/> + <xsd:enumeration value="tomorrow"/> + <xsd:enumeration value="today"/> + <xsd:enumeration value="yesterday"/> + <xsd:enumeration value="nextWeek"/> + <xsd:enumeration value="thisWeek"/> + <xsd:enumeration value="lastWeek"/> + <xsd:enumeration value="nextMonth"/> + <xsd:enumeration value="thisMonth"/> + <xsd:enumeration value="lastMonth"/> + <xsd:enumeration value="nextQuarter"/> + <xsd:enumeration value="thisQuarter"/> + <xsd:enumeration value="lastQuarter"/> + <xsd:enumeration value="nextYear"/> + <xsd:enumeration value="thisYear"/> + <xsd:enumeration value="lastYear"/> + <xsd:enumeration value="yearToDate"/> + <xsd:enumeration value="Q1"/> + <xsd:enumeration value="Q2"/> + <xsd:enumeration value="Q3"/> + <xsd:enumeration value="Q4"/> + <xsd:enumeration value="M1"/> + <xsd:enumeration value="M2"/> + <xsd:enumeration value="M3"/> + <xsd:enumeration value="M4"/> + <xsd:enumeration value="M5"/> + <xsd:enumeration value="M6"/> + <xsd:enumeration value="M7"/> + <xsd:enumeration value="M8"/> + <xsd:enumeration value="M9"/> + <xsd:enumeration value="M10"/> + <xsd:enumeration value="M11"/> + <xsd:enumeration value="M12"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PivotArea"> + <xsd:sequence> + <xsd:element name="references" minOccurs="0" type="CT_PivotAreaReferences"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="field" use="optional" type="xsd:int"/> + <xsd:attribute name="type" type="ST_PivotAreaType" default="normal"/> + <xsd:attribute name="dataOnly" type="xsd:boolean" default="true"/> + <xsd:attribute name="labelOnly" type="xsd:boolean" default="false"/> + <xsd:attribute name="grandRow" type="xsd:boolean" default="false"/> + <xsd:attribute name="grandCol" type="xsd:boolean" default="false"/> + <xsd:attribute name="cacheIndex" type="xsd:boolean" default="false"/> + <xsd:attribute name="outline" type="xsd:boolean" default="true"/> + <xsd:attribute name="offset" type="ST_Ref"/> + <xsd:attribute name="collapsedLevelsAreSubtotals" type="xsd:boolean" default="false"/> + <xsd:attribute name="axis" type="ST_Axis" use="optional"/> + <xsd:attribute name="fieldPosition" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_PivotAreaType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="normal"/> + <xsd:enumeration value="data"/> + <xsd:enumeration value="all"/> + <xsd:enumeration value="origin"/> + <xsd:enumeration value="button"/> + <xsd:enumeration value="topEnd"/> + <xsd:enumeration value="topRight"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PivotAreaReferences"> + <xsd:sequence> + <xsd:element name="reference" maxOccurs="unbounded" type="CT_PivotAreaReference"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:complexType name="CT_PivotAreaReference"> + <xsd:sequence> + <xsd:element name="x" minOccurs="0" maxOccurs="unbounded" type="CT_Index"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="field" use="optional" type="xsd:unsignedInt"/> + <xsd:attribute name="count" type="xsd:unsignedInt"/> + <xsd:attribute name="selected" type="xsd:boolean" default="true"/> + <xsd:attribute name="byPosition" type="xsd:boolean" default="false"/> + <xsd:attribute name="relative" type="xsd:boolean" default="false"/> + <xsd:attribute name="defaultSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="sumSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="countASubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="avgSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="maxSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="minSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="productSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="countSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="stdDevSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="stdDevPSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="varSubtotal" type="xsd:boolean" default="false"/> + <xsd:attribute name="varPSubtotal" type="xsd:boolean" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_Index"> + <xsd:attribute name="v" use="required" type="xsd:unsignedInt"/> + </xsd:complexType> + <xsd:simpleType name="ST_Axis"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="axisRow"/> + <xsd:enumeration value="axisCol"/> + <xsd:enumeration value="axisPage"/> + <xsd:enumeration value="axisValues"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:element name="queryTable" type="CT_QueryTable"/> + <xsd:complexType name="CT_QueryTable"> + <xsd:sequence> + <xsd:element name="queryTableRefresh" type="CT_QueryTableRefresh" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="headers" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="rowNumbers" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="disableRefresh" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="backgroundRefresh" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="firstBackgroundRefresh" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="refreshOnLoad" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="growShrinkType" type="ST_GrowShrinkType" use="optional" + default="insertDelete"/> + <xsd:attribute name="fillFormulas" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="removeDataOnSave" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="disableEdit" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="preserveFormatting" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="adjustColumnWidth" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="intermediate" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="connectionId" type="xsd:unsignedInt" use="required"/> + <xsd:attributeGroup ref="AG_AutoFormat"/> + </xsd:complexType> + <xsd:complexType name="CT_QueryTableRefresh"> + <xsd:sequence> + <xsd:element name="queryTableFields" type="CT_QueryTableFields" minOccurs="1" maxOccurs="1"/> + <xsd:element name="queryTableDeletedFields" type="CT_QueryTableDeletedFields" minOccurs="0" + maxOccurs="1"/> + <xsd:element name="sortState" minOccurs="0" maxOccurs="1" type="CT_SortState"/> + <xsd:element name="extLst" minOccurs="0" maxOccurs="1" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="preserveSortFilterLayout" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="fieldIdWrapped" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="headersInLastRefresh" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="minimumVersion" type="xsd:unsignedByte" use="optional" default="0"/> + <xsd:attribute name="nextId" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute name="unboundColumnsLeft" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="unboundColumnsRight" type="xsd:unsignedInt" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_QueryTableDeletedFields"> + <xsd:sequence> + <xsd:element name="deletedField" type="CT_DeletedField" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_DeletedField"> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_QueryTableFields"> + <xsd:sequence> + <xsd:element name="queryTableField" type="CT_QueryTableField" minOccurs="0" + maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_QueryTableField"> + <xsd:sequence minOccurs="0"> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="name" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="dataBound" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="rowNumbers" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="fillFormulas" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="clipped" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="tableColumnId" type="xsd:unsignedInt" default="0"/> + </xsd:complexType> + <xsd:simpleType name="ST_GrowShrinkType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="insertDelete"/> + <xsd:enumeration value="insertClear"/> + <xsd:enumeration value="overwriteClear"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:element name="sst" type="CT_Sst"/> + <xsd:complexType name="CT_Sst"> + <xsd:sequence> + <xsd:element name="si" type="CT_Rst" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="uniqueCount" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_PhoneticType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="halfwidthKatakana"/> + <xsd:enumeration value="fullwidthKatakana"/> + <xsd:enumeration value="Hiragana"/> + <xsd:enumeration value="noConversion"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PhoneticAlignment"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="noControl"/> + <xsd:enumeration value="left"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="distributed"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PhoneticRun"> + <xsd:sequence> + <xsd:element name="t" type="s:ST_Xstring" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="sb" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="eb" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_RElt"> + <xsd:sequence> + <xsd:element name="rPr" type="CT_RPrElt" minOccurs="0" maxOccurs="1"/> + <xsd:element name="t" type="s:ST_Xstring" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_RPrElt"> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="rFont" type="CT_FontName" minOccurs="0" maxOccurs="1"/> + <xsd:element name="charset" type="CT_IntProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="family" type="CT_IntProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="b" type="CT_BooleanProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="i" type="CT_BooleanProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="strike" type="CT_BooleanProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="outline" type="CT_BooleanProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="shadow" type="CT_BooleanProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="condense" type="CT_BooleanProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extend" type="CT_BooleanProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="color" type="CT_Color" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sz" type="CT_FontSize" minOccurs="0" maxOccurs="1"/> + <xsd:element name="u" type="CT_UnderlineProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="vertAlign" type="CT_VerticalAlignFontProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="scheme" type="CT_FontScheme" minOccurs="0" maxOccurs="1"/> + </xsd:choice> + </xsd:complexType> + <xsd:complexType name="CT_Rst"> + <xsd:sequence> + <xsd:element name="t" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + <xsd:element name="r" type="CT_RElt" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rPh" type="CT_PhoneticRun" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="phoneticPr" minOccurs="0" maxOccurs="1" type="CT_PhoneticPr"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PhoneticPr"> + <xsd:attribute name="fontId" type="ST_FontId" use="required"/> + <xsd:attribute name="type" type="ST_PhoneticType" use="optional" default="fullwidthKatakana"/> + <xsd:attribute name="alignment" type="ST_PhoneticAlignment" use="optional" default="left"/> + </xsd:complexType> + <xsd:element name="headers" type="CT_RevisionHeaders"/> + <xsd:element name="revisions" type="CT_Revisions"/> + <xsd:complexType name="CT_RevisionHeaders"> + <xsd:sequence> + <xsd:element name="header" type="CT_RevisionHeader" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="guid" type="s:ST_Guid" use="required"/> + <xsd:attribute name="lastGuid" type="s:ST_Guid" use="optional"/> + <xsd:attribute name="shared" type="xsd:boolean" default="true"/> + <xsd:attribute name="diskRevisions" type="xsd:boolean" default="false"/> + <xsd:attribute name="history" type="xsd:boolean" default="true"/> + <xsd:attribute name="trackRevisions" type="xsd:boolean" default="true"/> + <xsd:attribute name="exclusive" type="xsd:boolean" default="false"/> + <xsd:attribute name="revisionId" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="version" type="xsd:int" default="1"/> + <xsd:attribute name="keepChangeHistory" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="protected" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="preserveHistory" type="xsd:unsignedInt" default="30"/> + </xsd:complexType> + <xsd:complexType name="CT_Revisions"> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="rrc" type="CT_RevisionRowColumn" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rm" type="CT_RevisionMove" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rcv" type="CT_RevisionCustomView" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rsnm" type="CT_RevisionSheetRename" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="ris" type="CT_RevisionInsertSheet" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rcc" type="CT_RevisionCellChange" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rfmt" type="CT_RevisionFormatting" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="raf" type="CT_RevisionAutoFormatting" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rdn" type="CT_RevisionDefinedName" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rcmt" type="CT_RevisionComment" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rqt" type="CT_RevisionQueryTableField" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rcft" type="CT_RevisionConflict" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:complexType> + <xsd:attributeGroup name="AG_RevData"> + <xsd:attribute name="rId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="ua" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="ra" type="xsd:boolean" use="optional" default="false"/> + </xsd:attributeGroup> + <xsd:complexType name="CT_RevisionHeader"> + <xsd:sequence> + <xsd:element name="sheetIdMap" minOccurs="1" maxOccurs="1" type="CT_SheetIdMap"/> + <xsd:element name="reviewedList" minOccurs="0" maxOccurs="1" type="CT_ReviewedRevisions"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="guid" type="s:ST_Guid" use="required"/> + <xsd:attribute name="dateTime" type="xsd:dateTime" use="required"/> + <xsd:attribute name="maxSheetId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="userName" type="s:ST_Xstring" use="required"/> + <xsd:attribute ref="r:id" use="required"/> + <xsd:attribute name="minRId" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="maxRId" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_SheetIdMap"> + <xsd:sequence> + <xsd:element name="sheetId" type="CT_SheetId" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_SheetId"> + <xsd:attribute name="val" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_ReviewedRevisions"> + <xsd:sequence> + <xsd:element name="reviewed" type="CT_Reviewed" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Reviewed"> + <xsd:attribute name="rId" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_UndoInfo"> + <xsd:attribute name="index" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="exp" type="ST_FormulaExpression" use="required"/> + <xsd:attribute name="ref3D" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="array" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="v" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="nf" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="cs" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="dr" type="ST_RefA" use="required"/> + <xsd:attribute name="dn" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="r" type="ST_CellRef" use="optional"/> + <xsd:attribute name="sId" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_RevisionRowColumn"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="undo" type="CT_UndoInfo" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rcc" type="CT_RevisionCellChange" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rfmt" type="CT_RevisionFormatting" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + <xsd:attributeGroup ref="AG_RevData"/> + <xsd:attribute name="sId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="eol" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="ref" type="ST_Ref" use="required"/> + <xsd:attribute name="action" type="ST_rwColActionType" use="required"/> + <xsd:attribute name="edge" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_RevisionMove"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="undo" type="CT_UndoInfo" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rcc" type="CT_RevisionCellChange" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rfmt" type="CT_RevisionFormatting" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + <xsd:attributeGroup ref="AG_RevData"/> + <xsd:attribute name="sheetId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="source" type="ST_Ref" use="required"/> + <xsd:attribute name="destination" type="ST_Ref" use="required"/> + <xsd:attribute name="sourceSheetId" type="xsd:unsignedInt" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_RevisionCustomView"> + <xsd:attribute name="guid" type="s:ST_Guid" use="required"/> + <xsd:attribute name="action" type="ST_RevisionAction" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_RevisionSheetRename"> + <xsd:sequence> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_RevData"/> + <xsd:attribute name="sheetId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="oldName" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="newName" type="s:ST_Xstring" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_RevisionInsertSheet"> + <xsd:attributeGroup ref="AG_RevData"/> + <xsd:attribute name="sheetId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="sheetPosition" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_RevisionCellChange"> + <xsd:sequence> + <xsd:element name="oc" type="CT_Cell" minOccurs="0" maxOccurs="1"/> + <xsd:element name="nc" type="CT_Cell" minOccurs="1" maxOccurs="1"/> + <xsd:element name="odxf" type="CT_Dxf" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ndxf" type="CT_Dxf" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_RevData"/> + <xsd:attribute name="sId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="odxf" type="xsd:boolean" default="false"/> + <xsd:attribute name="xfDxf" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="s" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="dxf" type="xsd:boolean" default="false"/> + <xsd:attribute name="numFmtId" type="ST_NumFmtId" use="optional"/> + <xsd:attribute name="quotePrefix" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="oldQuotePrefix" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="ph" type="xsd:boolean" default="false"/> + <xsd:attribute name="oldPh" type="xsd:boolean" default="false"/> + <xsd:attribute name="endOfListFormulaUpdate" type="xsd:boolean" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_RevisionFormatting"> + <xsd:sequence> + <xsd:element name="dxf" type="CT_Dxf" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="sheetId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="xfDxf" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="s" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="sqref" type="ST_Sqref" use="required"/> + <xsd:attribute name="start" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="length" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_RevisionAutoFormatting"> + <xsd:attribute name="sheetId" type="xsd:unsignedInt" use="required"/> + <xsd:attributeGroup ref="AG_AutoFormat"/> + <xsd:attribute name="ref" type="ST_Ref" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_RevisionComment"> + <xsd:attribute name="sheetId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="cell" type="ST_CellRef" use="required"/> + <xsd:attribute name="guid" type="s:ST_Guid" use="required"/> + <xsd:attribute name="action" type="ST_RevisionAction" default="add"/> + <xsd:attribute name="alwaysShow" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="old" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="hiddenRow" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="hiddenColumn" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="author" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="oldLength" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="newLength" type="xsd:unsignedInt" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_RevisionDefinedName"> + <xsd:sequence> + <xsd:element name="formula" type="ST_Formula" minOccurs="0" maxOccurs="1"/> + <xsd:element name="oldFormula" type="ST_Formula" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_RevData"/> + <xsd:attribute name="localSheetId" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="customView" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="function" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="oldFunction" type="xsd:boolean" default="false"/> + <xsd:attribute name="functionGroupId" type="xsd:unsignedByte" use="optional"/> + <xsd:attribute name="oldFunctionGroupId" type="xsd:unsignedByte" use="optional"/> + <xsd:attribute name="shortcutKey" type="xsd:unsignedByte" use="optional"/> + <xsd:attribute name="oldShortcutKey" type="xsd:unsignedByte" use="optional"/> + <xsd:attribute name="hidden" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="oldHidden" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="customMenu" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="oldCustomMenu" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="description" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="oldDescription" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="help" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="oldHelp" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="statusBar" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="oldStatusBar" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="comment" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="oldComment" type="s:ST_Xstring" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_RevisionConflict"> + <xsd:attributeGroup ref="AG_RevData"/> + <xsd:attribute name="sheetId" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_RevisionQueryTableField"> + <xsd:attribute name="sheetId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="ref" type="ST_Ref" use="required"/> + <xsd:attribute name="fieldId" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_rwColActionType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="insertRow"/> + <xsd:enumeration value="deleteRow"/> + <xsd:enumeration value="insertCol"/> + <xsd:enumeration value="deleteCol"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_RevisionAction"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="add"/> + <xsd:enumeration value="delete"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FormulaExpression"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="ref"/> + <xsd:enumeration value="refError"/> + <xsd:enumeration value="area"/> + <xsd:enumeration value="areaError"/> + <xsd:enumeration value="computedArea"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:element name="users" type="CT_Users"/> + <xsd:complexType name="CT_Users"> + <xsd:sequence> + <xsd:element name="userInfo" minOccurs="0" maxOccurs="256" type="CT_SharedUser"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_SharedUser"> + <xsd:sequence> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="guid" type="s:ST_Guid" use="required"/> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="id" type="xsd:int" use="required"/> + <xsd:attribute name="dateTime" type="xsd:dateTime" use="required"/> + </xsd:complexType> + <xsd:element name="worksheet" type="CT_Worksheet"/> + <xsd:element name="chartsheet" type="CT_Chartsheet"/> + <xsd:element name="dialogsheet" type="CT_Dialogsheet"/> + <xsd:complexType name="CT_Macrosheet"> + <xsd:sequence> + <xsd:element name="sheetPr" type="CT_SheetPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dimension" type="CT_SheetDimension" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sheetViews" type="CT_SheetViews" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sheetFormatPr" type="CT_SheetFormatPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cols" type="CT_Cols" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="sheetData" type="CT_SheetData" minOccurs="1" maxOccurs="1"/> + <xsd:element name="sheetProtection" type="CT_SheetProtection" minOccurs="0" maxOccurs="1"/> + <xsd:element name="autoFilter" type="CT_AutoFilter" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sortState" type="CT_SortState" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dataConsolidate" type="CT_DataConsolidate" minOccurs="0" maxOccurs="1"/> + <xsd:element name="customSheetViews" type="CT_CustomSheetViews" minOccurs="0" maxOccurs="1"/> + <xsd:element name="phoneticPr" type="CT_PhoneticPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="conditionalFormatting" type="CT_ConditionalFormatting" minOccurs="0" + maxOccurs="unbounded"/> + <xsd:element name="printOptions" type="CT_PrintOptions" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pageMargins" type="CT_PageMargins" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pageSetup" type="CT_PageSetup" minOccurs="0" maxOccurs="1"/> + <xsd:element name="headerFooter" type="CT_HeaderFooter" minOccurs="0" maxOccurs="1"/> + <xsd:element name="rowBreaks" type="CT_PageBreak" minOccurs="0" maxOccurs="1"/> + <xsd:element name="colBreaks" type="CT_PageBreak" minOccurs="0" maxOccurs="1"/> + <xsd:element name="customProperties" type="CT_CustomProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="drawing" type="CT_Drawing" minOccurs="0" maxOccurs="1"/> + <xsd:element name="legacyDrawing" type="CT_LegacyDrawing" minOccurs="0" maxOccurs="1"/> + <xsd:element name="legacyDrawingHF" type="CT_LegacyDrawing" minOccurs="0" maxOccurs="1"/> + <xsd:element name="drawingHF" type="CT_DrawingHF" minOccurs="0" maxOccurs="1"/> + <xsd:element name="picture" type="CT_SheetBackgroundPicture" minOccurs="0" maxOccurs="1"/> + <xsd:element name="oleObjects" type="CT_OleObjects" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Dialogsheet"> + <xsd:sequence> + <xsd:element name="sheetPr" minOccurs="0" type="CT_SheetPr"/> + <xsd:element name="sheetViews" minOccurs="0" type="CT_SheetViews"/> + <xsd:element name="sheetFormatPr" minOccurs="0" type="CT_SheetFormatPr"/> + <xsd:element name="sheetProtection" type="CT_SheetProtection" minOccurs="0" maxOccurs="1"/> + <xsd:element name="customSheetViews" minOccurs="0" type="CT_CustomSheetViews"/> + <xsd:element name="printOptions" minOccurs="0" type="CT_PrintOptions"/> + <xsd:element name="pageMargins" minOccurs="0" type="CT_PageMargins"/> + <xsd:element name="pageSetup" minOccurs="0" type="CT_PageSetup"/> + <xsd:element name="headerFooter" minOccurs="0" type="CT_HeaderFooter"/> + <xsd:element name="drawing" minOccurs="0" type="CT_Drawing"/> + <xsd:element name="legacyDrawing" minOccurs="0" type="CT_LegacyDrawing"/> + <xsd:element name="legacyDrawingHF" type="CT_LegacyDrawing" minOccurs="0" maxOccurs="1"/> + <xsd:element name="drawingHF" type="CT_DrawingHF" minOccurs="0" maxOccurs="1"/> + <xsd:element name="oleObjects" type="CT_OleObjects" minOccurs="0" maxOccurs="1"/> + <xsd:element name="controls" type="CT_Controls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Worksheet"> + <xsd:sequence> + <xsd:element name="sheetPr" type="CT_SheetPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dimension" type="CT_SheetDimension" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sheetViews" type="CT_SheetViews" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sheetFormatPr" type="CT_SheetFormatPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cols" type="CT_Cols" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="sheetData" type="CT_SheetData" minOccurs="1" maxOccurs="1"/> + <xsd:element name="sheetCalcPr" type="CT_SheetCalcPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sheetProtection" type="CT_SheetProtection" minOccurs="0" maxOccurs="1"/> + <xsd:element name="protectedRanges" type="CT_ProtectedRanges" minOccurs="0" maxOccurs="1"/> + <xsd:element name="scenarios" type="CT_Scenarios" minOccurs="0" maxOccurs="1"/> + <xsd:element name="autoFilter" type="CT_AutoFilter" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sortState" type="CT_SortState" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dataConsolidate" type="CT_DataConsolidate" minOccurs="0" maxOccurs="1"/> + <xsd:element name="customSheetViews" type="CT_CustomSheetViews" minOccurs="0" maxOccurs="1"/> + <xsd:element name="mergeCells" type="CT_MergeCells" minOccurs="0" maxOccurs="1"/> + <xsd:element name="phoneticPr" type="CT_PhoneticPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="conditionalFormatting" type="CT_ConditionalFormatting" minOccurs="0" + maxOccurs="unbounded"/> + <xsd:element name="dataValidations" type="CT_DataValidations" minOccurs="0" maxOccurs="1"/> + <xsd:element name="hyperlinks" type="CT_Hyperlinks" minOccurs="0" maxOccurs="1"/> + <xsd:element name="printOptions" type="CT_PrintOptions" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pageMargins" type="CT_PageMargins" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pageSetup" type="CT_PageSetup" minOccurs="0" maxOccurs="1"/> + <xsd:element name="headerFooter" type="CT_HeaderFooter" minOccurs="0" maxOccurs="1"/> + <xsd:element name="rowBreaks" type="CT_PageBreak" minOccurs="0" maxOccurs="1"/> + <xsd:element name="colBreaks" type="CT_PageBreak" minOccurs="0" maxOccurs="1"/> + <xsd:element name="customProperties" type="CT_CustomProperties" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cellWatches" type="CT_CellWatches" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ignoredErrors" type="CT_IgnoredErrors" minOccurs="0" maxOccurs="1"/> + <xsd:element name="smartTags" type="CT_SmartTags" minOccurs="0" maxOccurs="1"/> + <xsd:element name="drawing" type="CT_Drawing" minOccurs="0" maxOccurs="1"/> + <xsd:element name="legacyDrawing" type="CT_LegacyDrawing" minOccurs="0" maxOccurs="1"/> + <xsd:element name="legacyDrawingHF" type="CT_LegacyDrawing" minOccurs="0" maxOccurs="1"/> + <xsd:element name="drawingHF" type="CT_DrawingHF" minOccurs="0" maxOccurs="1"/> + <xsd:element name="picture" type="CT_SheetBackgroundPicture" minOccurs="0" maxOccurs="1"/> + <xsd:element name="oleObjects" type="CT_OleObjects" minOccurs="0" maxOccurs="1"/> + <xsd:element name="controls" type="CT_Controls" minOccurs="0" maxOccurs="1"/> + <xsd:element name="webPublishItems" type="CT_WebPublishItems" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tableParts" type="CT_TableParts" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SheetData"> + <xsd:sequence> + <xsd:element name="row" type="CT_Row" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SheetCalcPr"> + <xsd:attribute name="fullCalcOnLoad" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_SheetFormatPr"> + <xsd:attribute name="baseColWidth" type="xsd:unsignedInt" use="optional" default="8"/> + <xsd:attribute name="defaultColWidth" type="xsd:double" use="optional"/> + <xsd:attribute name="defaultRowHeight" type="xsd:double" use="required"/> + <xsd:attribute name="customHeight" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="zeroHeight" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="thickTop" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="thickBottom" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="outlineLevelRow" type="xsd:unsignedByte" use="optional" default="0"/> + <xsd:attribute name="outlineLevelCol" type="xsd:unsignedByte" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_Cols"> + <xsd:sequence> + <xsd:element name="col" type="CT_Col" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Col"> + <xsd:attribute name="min" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="max" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="width" type="xsd:double" use="optional"/> + <xsd:attribute name="style" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="hidden" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="bestFit" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="customWidth" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="phonetic" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="outlineLevel" type="xsd:unsignedByte" use="optional" default="0"/> + <xsd:attribute name="collapsed" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:simpleType name="ST_CellSpan"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="ST_CellSpans"> + <xsd:list itemType="ST_CellSpan"/> + </xsd:simpleType> + <xsd:complexType name="CT_Row"> + <xsd:sequence> + <xsd:element name="c" type="CT_Cell" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="r" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="spans" type="ST_CellSpans" use="optional"/> + <xsd:attribute name="s" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="customFormat" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="ht" type="xsd:double" use="optional"/> + <xsd:attribute name="hidden" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="customHeight" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="outlineLevel" type="xsd:unsignedByte" use="optional" default="0"/> + <xsd:attribute name="collapsed" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="thickTop" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="thickBot" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="ph" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_Cell"> + <xsd:sequence> + <xsd:element name="f" type="CT_CellFormula" minOccurs="0" maxOccurs="1"/> + <xsd:element name="v" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + <xsd:element name="is" type="CT_Rst" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="r" type="ST_CellRef" use="optional"/> + <xsd:attribute name="s" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="t" type="ST_CellType" use="optional" default="n"/> + <xsd:attribute name="cm" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="vm" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="ph" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:simpleType name="ST_CellType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="b"/> + <xsd:enumeration value="n"/> + <xsd:enumeration value="e"/> + <xsd:enumeration value="s"/> + <xsd:enumeration value="str"/> + <xsd:enumeration value="inlineStr"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_CellFormulaType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="normal"/> + <xsd:enumeration value="array"/> + <xsd:enumeration value="dataTable"/> + <xsd:enumeration value="shared"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SheetPr"> + <xsd:sequence> + <xsd:element name="tabColor" type="CT_Color" minOccurs="0" maxOccurs="1"/> + <xsd:element name="outlinePr" type="CT_OutlinePr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pageSetUpPr" type="CT_PageSetUpPr" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="syncHorizontal" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="syncVertical" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="syncRef" type="ST_Ref" use="optional"/> + <xsd:attribute name="transitionEvaluation" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="transitionEntry" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="published" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="codeName" type="xsd:string" use="optional"/> + <xsd:attribute name="filterMode" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="enableFormatConditionsCalculation" type="xsd:boolean" use="optional" + default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_SheetDimension"> + <xsd:attribute name="ref" type="ST_Ref" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SheetViews"> + <xsd:sequence> + <xsd:element name="sheetView" type="CT_SheetView" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SheetView"> + <xsd:sequence> + <xsd:element name="pane" type="CT_Pane" minOccurs="0" maxOccurs="1"/> + <xsd:element name="selection" type="CT_Selection" minOccurs="0" maxOccurs="4"/> + <xsd:element name="pivotSelection" type="CT_PivotSelection" minOccurs="0" maxOccurs="4"/> + <xsd:element name="extLst" minOccurs="0" maxOccurs="1" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="windowProtection" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showFormulas" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showGridLines" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="showRowColHeaders" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="showZeros" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="rightToLeft" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="tabSelected" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showRuler" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="showOutlineSymbols" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="defaultGridColor" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="showWhiteSpace" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="view" type="ST_SheetViewType" use="optional" default="normal"/> + <xsd:attribute name="topLeftCell" type="ST_CellRef" use="optional"/> + <xsd:attribute name="colorId" type="xsd:unsignedInt" use="optional" default="64"/> + <xsd:attribute name="zoomScale" type="xsd:unsignedInt" use="optional" default="100"/> + <xsd:attribute name="zoomScaleNormal" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="zoomScaleSheetLayoutView" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="zoomScalePageLayoutView" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="workbookViewId" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Pane"> + <xsd:attribute name="xSplit" type="xsd:double" use="optional" default="0"/> + <xsd:attribute name="ySplit" type="xsd:double" use="optional" default="0"/> + <xsd:attribute name="topLeftCell" type="ST_CellRef" use="optional"/> + <xsd:attribute name="activePane" type="ST_Pane" use="optional" default="topLeft"/> + <xsd:attribute name="state" type="ST_PaneState" use="optional" default="split"/> + </xsd:complexType> + <xsd:complexType name="CT_PivotSelection"> + <xsd:sequence> + <xsd:element name="pivotArea" type="CT_PivotArea"/> + </xsd:sequence> + <xsd:attribute name="pane" type="ST_Pane" use="optional" default="topLeft"/> + <xsd:attribute name="showHeader" type="xsd:boolean" default="false"/> + <xsd:attribute name="label" type="xsd:boolean" default="false"/> + <xsd:attribute name="data" type="xsd:boolean" default="false"/> + <xsd:attribute name="extendable" type="xsd:boolean" default="false"/> + <xsd:attribute name="count" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="axis" type="ST_Axis" use="optional"/> + <xsd:attribute name="dimension" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="start" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="min" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="max" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="activeRow" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="activeCol" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="previousRow" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="previousCol" type="xsd:unsignedInt" default="0"/> + <xsd:attribute name="click" type="xsd:unsignedInt" default="0"/> + <xsd:attribute ref="r:id" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Selection"> + <xsd:attribute name="pane" type="ST_Pane" use="optional" default="topLeft"/> + <xsd:attribute name="activeCell" type="ST_CellRef" use="optional"/> + <xsd:attribute name="activeCellId" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="sqref" type="ST_Sqref" use="optional" default="A1"/> + </xsd:complexType> + <xsd:simpleType name="ST_Pane"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="bottomRight"/> + <xsd:enumeration value="topRight"/> + <xsd:enumeration value="bottomLeft"/> + <xsd:enumeration value="topLeft"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PageBreak"> + <xsd:sequence> + <xsd:element name="brk" type="CT_Break" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="manualBreakCount" type="xsd:unsignedInt" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_Break"> + <xsd:attribute name="id" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="min" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="max" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="man" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="pt" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:simpleType name="ST_SheetViewType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="normal"/> + <xsd:enumeration value="pageBreakPreview"/> + <xsd:enumeration value="pageLayout"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_OutlinePr"> + <xsd:attribute name="applyStyles" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="summaryBelow" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="summaryRight" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="showOutlineSymbols" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_PageSetUpPr"> + <xsd:attribute name="autoPageBreaks" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="fitToPage" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_DataConsolidate"> + <xsd:sequence> + <xsd:element name="dataRefs" type="CT_DataRefs" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="function" type="ST_DataConsolidateFunction" use="optional" default="sum"/> + <xsd:attribute name="startLabels" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="leftLabels" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="topLabels" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="link" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:simpleType name="ST_DataConsolidateFunction"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="average"/> + <xsd:enumeration value="count"/> + <xsd:enumeration value="countNums"/> + <xsd:enumeration value="max"/> + <xsd:enumeration value="min"/> + <xsd:enumeration value="product"/> + <xsd:enumeration value="stdDev"/> + <xsd:enumeration value="stdDevp"/> + <xsd:enumeration value="sum"/> + <xsd:enumeration value="var"/> + <xsd:enumeration value="varp"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_DataRefs"> + <xsd:sequence> + <xsd:element name="dataRef" type="CT_DataRef" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_DataRef"> + <xsd:attribute name="ref" type="ST_Ref" use="optional"/> + <xsd:attribute name="name" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="sheet" type="s:ST_Xstring" use="optional"/> + <xsd:attribute ref="r:id" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_MergeCells"> + <xsd:sequence> + <xsd:element name="mergeCell" type="CT_MergeCell" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_MergeCell"> + <xsd:attribute name="ref" type="ST_Ref" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SmartTags"> + <xsd:sequence> + <xsd:element name="cellSmartTags" type="CT_CellSmartTags" minOccurs="1" maxOccurs="unbounded" + /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CellSmartTags"> + <xsd:sequence> + <xsd:element name="cellSmartTag" type="CT_CellSmartTag" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="r" type="ST_CellRef" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CellSmartTag"> + <xsd:sequence> + <xsd:element name="cellSmartTagPr" minOccurs="0" maxOccurs="unbounded" + type="CT_CellSmartTagPr"/> + </xsd:sequence> + <xsd:attribute name="type" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="deleted" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="xmlBased" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_CellSmartTagPr"> + <xsd:attribute name="key" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="val" type="s:ST_Xstring" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Drawing"> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_LegacyDrawing"> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_DrawingHF"> + <xsd:attribute ref="r:id" use="required"/> + <xsd:attribute name="lho" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="lhe" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="lhf" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="cho" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="che" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="chf" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="rho" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="rhe" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="rhf" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="lfo" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="lfe" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="lff" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="cfo" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="cfe" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="cff" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="rfo" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="rfe" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="rff" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomSheetViews"> + <xsd:sequence> + <xsd:element name="customSheetView" minOccurs="1" maxOccurs="unbounded" + type="CT_CustomSheetView"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CustomSheetView"> + <xsd:sequence> + <xsd:element name="pane" type="CT_Pane" minOccurs="0" maxOccurs="1"/> + <xsd:element name="selection" type="CT_Selection" minOccurs="0" maxOccurs="1"/> + <xsd:element name="rowBreaks" type="CT_PageBreak" minOccurs="0" maxOccurs="1"/> + <xsd:element name="colBreaks" type="CT_PageBreak" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pageMargins" type="CT_PageMargins" minOccurs="0" maxOccurs="1"/> + <xsd:element name="printOptions" type="CT_PrintOptions" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pageSetup" type="CT_PageSetup" minOccurs="0" maxOccurs="1"/> + <xsd:element name="headerFooter" type="CT_HeaderFooter" minOccurs="0" maxOccurs="1"/> + <xsd:element name="autoFilter" type="CT_AutoFilter" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="guid" type="s:ST_Guid" use="required"/> + <xsd:attribute name="scale" type="xsd:unsignedInt" default="100"/> + <xsd:attribute name="colorId" type="xsd:unsignedInt" default="64"/> + <xsd:attribute name="showPageBreaks" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showFormulas" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showGridLines" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="showRowCol" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="outlineSymbols" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="zeroValues" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="fitToPage" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="printArea" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="filter" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showAutoFilter" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="hiddenRows" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="hiddenColumns" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="state" type="ST_SheetState" default="visible"/> + <xsd:attribute name="filterUnique" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="view" type="ST_SheetViewType" default="normal"/> + <xsd:attribute name="showRuler" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="topLeftCell" type="ST_CellRef" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_DataValidations"> + <xsd:sequence> + <xsd:element name="dataValidation" type="CT_DataValidation" minOccurs="1" + maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="disablePrompts" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="xWindow" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="yWindow" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_DataValidation"> + <xsd:sequence> + <xsd:element name="formula1" type="ST_Formula" minOccurs="0" maxOccurs="1"/> + <xsd:element name="formula2" type="ST_Formula" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="type" type="ST_DataValidationType" use="optional" default="none"/> + <xsd:attribute name="errorStyle" type="ST_DataValidationErrorStyle" use="optional" + default="stop"/> + <xsd:attribute name="imeMode" type="ST_DataValidationImeMode" use="optional" default="noControl"/> + <xsd:attribute name="operator" type="ST_DataValidationOperator" use="optional" default="between"/> + <xsd:attribute name="allowBlank" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showDropDown" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showInputMessage" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showErrorMessage" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="errorTitle" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="error" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="promptTitle" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="prompt" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="sqref" type="ST_Sqref" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_DataValidationType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="whole"/> + <xsd:enumeration value="decimal"/> + <xsd:enumeration value="list"/> + <xsd:enumeration value="date"/> + <xsd:enumeration value="time"/> + <xsd:enumeration value="textLength"/> + <xsd:enumeration value="custom"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_DataValidationOperator"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="between"/> + <xsd:enumeration value="notBetween"/> + <xsd:enumeration value="equal"/> + <xsd:enumeration value="notEqual"/> + <xsd:enumeration value="lessThan"/> + <xsd:enumeration value="lessThanOrEqual"/> + <xsd:enumeration value="greaterThan"/> + <xsd:enumeration value="greaterThanOrEqual"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_DataValidationErrorStyle"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="stop"/> + <xsd:enumeration value="warning"/> + <xsd:enumeration value="information"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_DataValidationImeMode"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="noControl"/> + <xsd:enumeration value="off"/> + <xsd:enumeration value="on"/> + <xsd:enumeration value="disabled"/> + <xsd:enumeration value="hiragana"/> + <xsd:enumeration value="fullKatakana"/> + <xsd:enumeration value="halfKatakana"/> + <xsd:enumeration value="fullAlpha"/> + <xsd:enumeration value="halfAlpha"/> + <xsd:enumeration value="fullHangul"/> + <xsd:enumeration value="halfHangul"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_CfType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="expression"/> + <xsd:enumeration value="cellIs"/> + <xsd:enumeration value="colorScale"/> + <xsd:enumeration value="dataBar"/> + <xsd:enumeration value="iconSet"/> + <xsd:enumeration value="top10"/> + <xsd:enumeration value="uniqueValues"/> + <xsd:enumeration value="duplicateValues"/> + <xsd:enumeration value="containsText"/> + <xsd:enumeration value="notContainsText"/> + <xsd:enumeration value="beginsWith"/> + <xsd:enumeration value="endsWith"/> + <xsd:enumeration value="containsBlanks"/> + <xsd:enumeration value="notContainsBlanks"/> + <xsd:enumeration value="containsErrors"/> + <xsd:enumeration value="notContainsErrors"/> + <xsd:enumeration value="timePeriod"/> + <xsd:enumeration value="aboveAverage"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TimePeriod"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="today"/> + <xsd:enumeration value="yesterday"/> + <xsd:enumeration value="tomorrow"/> + <xsd:enumeration value="last7Days"/> + <xsd:enumeration value="thisMonth"/> + <xsd:enumeration value="lastMonth"/> + <xsd:enumeration value="nextMonth"/> + <xsd:enumeration value="thisWeek"/> + <xsd:enumeration value="lastWeek"/> + <xsd:enumeration value="nextWeek"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ConditionalFormattingOperator"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="lessThan"/> + <xsd:enumeration value="lessThanOrEqual"/> + <xsd:enumeration value="equal"/> + <xsd:enumeration value="notEqual"/> + <xsd:enumeration value="greaterThanOrEqual"/> + <xsd:enumeration value="greaterThan"/> + <xsd:enumeration value="between"/> + <xsd:enumeration value="notBetween"/> + <xsd:enumeration value="containsText"/> + <xsd:enumeration value="notContains"/> + <xsd:enumeration value="beginsWith"/> + <xsd:enumeration value="endsWith"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_CfvoType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="num"/> + <xsd:enumeration value="percent"/> + <xsd:enumeration value="max"/> + <xsd:enumeration value="min"/> + <xsd:enumeration value="formula"/> + <xsd:enumeration value="percentile"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_ConditionalFormatting"> + <xsd:sequence> + <xsd:element name="cfRule" type="CT_CfRule" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="pivot" type="xsd:boolean" default="false"/> + <xsd:attribute name="sqref" type="ST_Sqref"/> + </xsd:complexType> + <xsd:complexType name="CT_CfRule"> + <xsd:sequence> + <xsd:element name="formula" type="ST_Formula" minOccurs="0" maxOccurs="3"/> + <xsd:element name="colorScale" type="CT_ColorScale" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dataBar" type="CT_DataBar" minOccurs="0" maxOccurs="1"/> + <xsd:element name="iconSet" type="CT_IconSet" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="type" type="ST_CfType"/> + <xsd:attribute name="dxfId" type="ST_DxfId" use="optional"/> + <xsd:attribute name="priority" type="xsd:int" use="required"/> + <xsd:attribute name="stopIfTrue" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="aboveAverage" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="percent" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="bottom" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="operator" type="ST_ConditionalFormattingOperator" use="optional"/> + <xsd:attribute name="text" type="xsd:string" use="optional"/> + <xsd:attribute name="timePeriod" type="ST_TimePeriod" use="optional"/> + <xsd:attribute name="rank" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="stdDev" type="xsd:int" use="optional"/> + <xsd:attribute name="equalAverage" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_Hyperlinks"> + <xsd:sequence> + <xsd:element name="hyperlink" type="CT_Hyperlink" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Hyperlink"> + <xsd:attribute name="ref" type="ST_Ref" use="required"/> + <xsd:attribute ref="r:id" use="optional"/> + <xsd:attribute name="location" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="tooltip" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="display" type="s:ST_Xstring" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_CellFormula"> + <xsd:simpleContent> + <xsd:extension base="ST_Formula"> + <xsd:attribute name="t" type="ST_CellFormulaType" use="optional" default="normal"/> + <xsd:attribute name="aca" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="ref" type="ST_Ref" use="optional"/> + <xsd:attribute name="dt2D" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="dtr" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="del1" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="del2" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="r1" type="ST_CellRef" use="optional"/> + <xsd:attribute name="r2" type="ST_CellRef" use="optional"/> + <xsd:attribute name="ca" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="si" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="bx" type="xsd:boolean" use="optional" default="false"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + <xsd:complexType name="CT_ColorScale"> + <xsd:sequence> + <xsd:element name="cfvo" type="CT_Cfvo" minOccurs="2" maxOccurs="unbounded"/> + <xsd:element name="color" type="CT_Color" minOccurs="2" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DataBar"> + <xsd:sequence> + <xsd:element name="cfvo" type="CT_Cfvo" minOccurs="2" maxOccurs="2"/> + <xsd:element name="color" type="CT_Color" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="minLength" type="xsd:unsignedInt" use="optional" default="10"/> + <xsd:attribute name="maxLength" type="xsd:unsignedInt" use="optional" default="90"/> + <xsd:attribute name="showValue" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_IconSet"> + <xsd:sequence> + <xsd:element name="cfvo" type="CT_Cfvo" minOccurs="2" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="iconSet" type="ST_IconSetType" use="optional" default="3TrafficLights1"/> + <xsd:attribute name="showValue" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="percent" type="xsd:boolean" default="true"/> + <xsd:attribute name="reverse" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_Cfvo"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="type" type="ST_CfvoType" use="required"/> + <xsd:attribute name="val" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="gte" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_PageMargins"> + <xsd:attribute name="left" type="xsd:double" use="required"/> + <xsd:attribute name="right" type="xsd:double" use="required"/> + <xsd:attribute name="top" type="xsd:double" use="required"/> + <xsd:attribute name="bottom" type="xsd:double" use="required"/> + <xsd:attribute name="header" type="xsd:double" use="required"/> + <xsd:attribute name="footer" type="xsd:double" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_PrintOptions"> + <xsd:attribute name="horizontalCentered" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="verticalCentered" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="headings" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="gridLines" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="gridLinesSet" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_PageSetup"> + <xsd:attribute name="paperSize" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute name="paperHeight" type="s:ST_PositiveUniversalMeasure" use="optional"/> + <xsd:attribute name="paperWidth" type="s:ST_PositiveUniversalMeasure" use="optional"/> + <xsd:attribute name="scale" type="xsd:unsignedInt" use="optional" default="100"/> + <xsd:attribute name="firstPageNumber" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute name="fitToWidth" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute name="fitToHeight" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute name="pageOrder" type="ST_PageOrder" use="optional" default="downThenOver"/> + <xsd:attribute name="orientation" type="ST_Orientation" use="optional" default="default"/> + <xsd:attribute name="usePrinterDefaults" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="blackAndWhite" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="draft" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="cellComments" type="ST_CellComments" use="optional" default="none"/> + <xsd:attribute name="useFirstPageNumber" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="errors" type="ST_PrintError" use="optional" default="displayed"/> + <xsd:attribute name="horizontalDpi" type="xsd:unsignedInt" use="optional" default="600"/> + <xsd:attribute name="verticalDpi" type="xsd:unsignedInt" use="optional" default="600"/> + <xsd:attribute name="copies" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute ref="r:id" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_PageOrder"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="downThenOver"/> + <xsd:enumeration value="overThenDown"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Orientation"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="default"/> + <xsd:enumeration value="portrait"/> + <xsd:enumeration value="landscape"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_CellComments"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="asDisplayed"/> + <xsd:enumeration value="atEnd"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_HeaderFooter"> + <xsd:sequence> + <xsd:element name="oddHeader" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + <xsd:element name="oddFooter" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + <xsd:element name="evenHeader" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + <xsd:element name="evenFooter" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + <xsd:element name="firstHeader" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + <xsd:element name="firstFooter" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="differentOddEven" type="xsd:boolean" default="false"/> + <xsd:attribute name="differentFirst" type="xsd:boolean" default="false"/> + <xsd:attribute name="scaleWithDoc" type="xsd:boolean" default="true"/> + <xsd:attribute name="alignWithMargins" type="xsd:boolean" default="true"/> + </xsd:complexType> + <xsd:simpleType name="ST_PrintError"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="displayed"/> + <xsd:enumeration value="blank"/> + <xsd:enumeration value="dash"/> + <xsd:enumeration value="NA"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Scenarios"> + <xsd:sequence> + <xsd:element name="scenario" type="CT_Scenario" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="current" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="show" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="sqref" type="ST_Sqref" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_SheetProtection"> + <xsd:attribute name="password" type="ST_UnsignedShortHex" use="optional"/> + <xsd:attribute name="algorithmName" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="hashValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="saltValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="spinCount" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="sheet" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="objects" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="scenarios" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="formatCells" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="formatColumns" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="formatRows" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="insertColumns" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="insertRows" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="insertHyperlinks" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="deleteColumns" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="deleteRows" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="selectLockedCells" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="sort" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="autoFilter" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="pivotTables" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="selectUnlockedCells" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_ProtectedRanges"> + <xsd:sequence> + <xsd:element name="protectedRange" type="CT_ProtectedRange" minOccurs="1" + maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ProtectedRange"> + <xsd:sequence> + <xsd:element name="securityDescriptor" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="password" type="ST_UnsignedShortHex" use="optional"/> + <xsd:attribute name="sqref" type="ST_Sqref" use="required"/> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="securityDescriptor" type="xsd:string" use="optional"/> + <xsd:attribute name="algorithmName" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="hashValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="saltValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="spinCount" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Scenario"> + <xsd:sequence> + <xsd:element name="inputCells" type="CT_InputCells" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="locked" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="hidden" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="user" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="comment" type="s:ST_Xstring" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_InputCells"> + <xsd:attribute name="r" type="ST_CellRef" use="required"/> + <xsd:attribute name="deleted" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="undone" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="val" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="numFmtId" type="ST_NumFmtId" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_CellWatches"> + <xsd:sequence> + <xsd:element name="cellWatch" type="CT_CellWatch" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CellWatch"> + <xsd:attribute name="r" type="ST_CellRef" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Chartsheet"> + <xsd:sequence> + <xsd:element name="sheetPr" type="CT_ChartsheetPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sheetViews" type="CT_ChartsheetViews" minOccurs="1" maxOccurs="1"/> + <xsd:element name="sheetProtection" type="CT_ChartsheetProtection" minOccurs="0" maxOccurs="1"/> + <xsd:element name="customSheetViews" type="CT_CustomChartsheetViews" minOccurs="0" + maxOccurs="1"/> + <xsd:element name="pageMargins" minOccurs="0" type="CT_PageMargins"/> + <xsd:element name="pageSetup" type="CT_CsPageSetup" minOccurs="0" maxOccurs="1"/> + <xsd:element name="headerFooter" minOccurs="0" type="CT_HeaderFooter"/> + <xsd:element name="drawing" type="CT_Drawing" minOccurs="1" maxOccurs="1"/> + <xsd:element name="legacyDrawing" type="CT_LegacyDrawing" minOccurs="0" maxOccurs="1"/> + <xsd:element name="legacyDrawingHF" type="CT_LegacyDrawing" minOccurs="0" maxOccurs="1"/> + <xsd:element name="drawingHF" type="CT_DrawingHF" minOccurs="0" maxOccurs="1"/> + <xsd:element name="picture" type="CT_SheetBackgroundPicture" minOccurs="0" maxOccurs="1"/> + <xsd:element name="webPublishItems" type="CT_WebPublishItems" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ChartsheetPr"> + <xsd:sequence> + <xsd:element name="tabColor" type="CT_Color" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="published" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="codeName" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_ChartsheetViews"> + <xsd:sequence> + <xsd:element name="sheetView" type="CT_ChartsheetView" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ChartsheetView"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="tabSelected" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="zoomScale" type="xsd:unsignedInt" default="100" use="optional"/> + <xsd:attribute name="workbookViewId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="zoomToFit" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_ChartsheetProtection"> + <xsd:attribute name="password" type="ST_UnsignedShortHex" use="optional"/> + <xsd:attribute name="algorithmName" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="hashValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="saltValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="spinCount" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="content" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="objects" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_CsPageSetup"> + <xsd:attribute name="paperSize" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute name="paperHeight" type="s:ST_PositiveUniversalMeasure" use="optional"/> + <xsd:attribute name="paperWidth" type="s:ST_PositiveUniversalMeasure" use="optional"/> + <xsd:attribute name="firstPageNumber" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute name="orientation" type="ST_Orientation" use="optional" default="default"/> + <xsd:attribute name="usePrinterDefaults" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="blackAndWhite" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="draft" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="useFirstPageNumber" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="horizontalDpi" type="xsd:unsignedInt" use="optional" default="600"/> + <xsd:attribute name="verticalDpi" type="xsd:unsignedInt" use="optional" default="600"/> + <xsd:attribute name="copies" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute ref="r:id" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomChartsheetViews"> + <xsd:sequence> + <xsd:element name="customSheetView" minOccurs="0" maxOccurs="unbounded" + type="CT_CustomChartsheetView"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CustomChartsheetView"> + <xsd:sequence> + <xsd:element name="pageMargins" type="CT_PageMargins" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pageSetup" type="CT_CsPageSetup" minOccurs="0" maxOccurs="1"/> + <xsd:element name="headerFooter" type="CT_HeaderFooter" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="guid" type="s:ST_Guid" use="required"/> + <xsd:attribute name="scale" type="xsd:unsignedInt" default="100"/> + <xsd:attribute name="state" type="ST_SheetState" default="visible"/> + <xsd:attribute name="zoomToFit" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomProperties"> + <xsd:sequence> + <xsd:element name="customPr" type="CT_CustomProperty" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CustomProperty"> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_OleObjects"> + <xsd:sequence> + <xsd:element name="oleObject" type="CT_OleObject" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_OleObject"> + <xsd:sequence> + <xsd:element name="objectPr" type="CT_ObjectPr" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="progId" type="xsd:string" use="optional"/> + <xsd:attribute name="dvAspect" type="ST_DvAspect" use="optional" default="DVASPECT_CONTENT"/> + <xsd:attribute name="link" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="oleUpdate" type="ST_OleUpdate" use="optional"/> + <xsd:attribute name="autoLoad" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="shapeId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute ref="r:id" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_ObjectPr"> + <xsd:sequence> + <xsd:element name="anchor" type="CT_ObjectAnchor" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="locked" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="defaultSize" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="print" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="disabled" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="uiObject" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="autoFill" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="autoLine" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="autoPict" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="macro" type="ST_Formula" use="optional"/> + <xsd:attribute name="altText" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="dde" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute ref="r:id" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_DvAspect"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="DVASPECT_CONTENT"/> + <xsd:enumeration value="DVASPECT_ICON"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_OleUpdate"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="OLEUPDATE_ALWAYS"/> + <xsd:enumeration value="OLEUPDATE_ONCALL"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_WebPublishItems"> + <xsd:sequence> + <xsd:element name="webPublishItem" type="CT_WebPublishItem" minOccurs="1" + maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_WebPublishItem"> + <xsd:attribute name="id" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="divId" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="sourceType" type="ST_WebSourceType" use="required"/> + <xsd:attribute name="sourceRef" type="ST_Ref" use="optional"/> + <xsd:attribute name="sourceObject" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="destinationFile" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="title" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="autoRepublish" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_Controls"> + <xsd:sequence> + <xsd:element name="control" type="CT_Control" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Control"> + <xsd:sequence> + <xsd:element name="controlPr" type="CT_ControlPr" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="shapeId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute ref="r:id" use="required"/> + <xsd:attribute name="name" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_ControlPr"> + <xsd:sequence> + <xsd:element name="anchor" type="CT_ObjectAnchor" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="locked" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="defaultSize" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="print" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="disabled" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="recalcAlways" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="uiObject" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="autoFill" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="autoLine" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="autoPict" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="macro" type="ST_Formula" use="optional"/> + <xsd:attribute name="altText" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="linkedCell" type="ST_Formula" use="optional"/> + <xsd:attribute name="listFillRange" type="ST_Formula" use="optional"/> + <xsd:attribute name="cf" type="s:ST_Xstring" use="optional" default="pict"/> + <xsd:attribute ref="r:id" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_WebSourceType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="sheet"/> + <xsd:enumeration value="printArea"/> + <xsd:enumeration value="autoFilter"/> + <xsd:enumeration value="range"/> + <xsd:enumeration value="chart"/> + <xsd:enumeration value="pivotTable"/> + <xsd:enumeration value="query"/> + <xsd:enumeration value="label"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_IgnoredErrors"> + <xsd:sequence> + <xsd:element name="ignoredError" type="CT_IgnoredError" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_IgnoredError"> + <xsd:attribute name="sqref" type="ST_Sqref" use="required"/> + <xsd:attribute name="evalError" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="twoDigitTextYear" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="numberStoredAsText" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="formula" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="formulaRange" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="unlockedFormula" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="emptyCellReference" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="listDataValidation" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="calculatedColumn" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:simpleType name="ST_PaneState"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="split"/> + <xsd:enumeration value="frozen"/> + <xsd:enumeration value="frozenSplit"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TableParts"> + <xsd:sequence> + <xsd:element name="tablePart" type="CT_TablePart" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TablePart"> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:element name="metadata" type="CT_Metadata"/> + <xsd:complexType name="CT_Metadata"> + <xsd:sequence> + <xsd:element name="metadataTypes" type="CT_MetadataTypes" minOccurs="0" maxOccurs="1"/> + <xsd:element name="metadataStrings" type="CT_MetadataStrings" minOccurs="0" maxOccurs="1"/> + <xsd:element name="mdxMetadata" type="CT_MdxMetadata" minOccurs="0" maxOccurs="1"/> + <xsd:element name="futureMetadata" type="CT_FutureMetadata" minOccurs="0" + maxOccurs="unbounded"/> + <xsd:element name="cellMetadata" type="CT_MetadataBlocks" minOccurs="0" maxOccurs="1"/> + <xsd:element name="valueMetadata" type="CT_MetadataBlocks" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" minOccurs="0" maxOccurs="1" type="CT_ExtensionList"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_MetadataTypes"> + <xsd:sequence> + <xsd:element name="metadataType" type="CT_MetadataType" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_MetadataType"> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="minSupportedVersion" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="ghostRow" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="ghostCol" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="edit" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="delete" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="copy" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="pasteAll" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="pasteFormulas" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="pasteValues" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="pasteFormats" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="pasteComments" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="pasteDataValidation" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="pasteBorders" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="pasteColWidths" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="pasteNumberFormats" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="merge" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="splitFirst" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="splitAll" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="rowColShift" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="clearAll" type="xsd:boolean" default="false"/> + <xsd:attribute name="clearFormats" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="clearContents" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="clearComments" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="assign" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="coerce" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="adjust" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="cellMeta" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_MetadataBlocks"> + <xsd:sequence> + <xsd:element name="bk" type="CT_MetadataBlock" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_MetadataBlock"> + <xsd:sequence> + <xsd:element name="rc" type="CT_MetadataRecord" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_MetadataRecord"> + <xsd:attribute name="t" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="v" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_FutureMetadata"> + <xsd:sequence> + <xsd:element name="bk" type="CT_FutureMetadataBlock" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="extLst" minOccurs="0" maxOccurs="1" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_FutureMetadataBlock"> + <xsd:sequence> + <xsd:element name="extLst" minOccurs="0" maxOccurs="1" type="CT_ExtensionList"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_MdxMetadata"> + <xsd:sequence> + <xsd:element name="mdx" type="CT_Mdx" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_Mdx"> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="t" type="CT_MdxTuple"/> + <xsd:element name="ms" type="CT_MdxSet"/> + <xsd:element name="p" type="CT_MdxMemeberProp"/> + <xsd:element name="k" type="CT_MdxKPI"/> + </xsd:choice> + <xsd:attribute name="n" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="f" type="ST_MdxFunctionType" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_MdxFunctionType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="m"/> + <xsd:enumeration value="v"/> + <xsd:enumeration value="s"/> + <xsd:enumeration value="c"/> + <xsd:enumeration value="r"/> + <xsd:enumeration value="p"/> + <xsd:enumeration value="k"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_MdxTuple"> + <xsd:sequence> + <xsd:element name="n" type="CT_MetadataStringIndex" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="c" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="ct" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="si" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="fi" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="bc" type="ST_UnsignedIntHex" use="optional"/> + <xsd:attribute name="fc" type="ST_UnsignedIntHex" use="optional"/> + <xsd:attribute name="i" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="u" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="st" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="b" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_MdxSet"> + <xsd:sequence> + <xsd:element name="n" type="CT_MetadataStringIndex" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="ns" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="c" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="o" type="ST_MdxSetOrder" use="optional" default="u"/> + </xsd:complexType> + <xsd:simpleType name="ST_MdxSetOrder"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="u"/> + <xsd:enumeration value="a"/> + <xsd:enumeration value="d"/> + <xsd:enumeration value="aa"/> + <xsd:enumeration value="ad"/> + <xsd:enumeration value="na"/> + <xsd:enumeration value="nd"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_MdxMemeberProp"> + <xsd:attribute name="n" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="np" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_MdxKPI"> + <xsd:attribute name="n" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="np" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="p" type="ST_MdxKPIProperty" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_MdxKPIProperty"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="v"/> + <xsd:enumeration value="g"/> + <xsd:enumeration value="s"/> + <xsd:enumeration value="t"/> + <xsd:enumeration value="w"/> + <xsd:enumeration value="m"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_MetadataStringIndex"> + <xsd:attribute name="x" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="s" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_MetadataStrings"> + <xsd:sequence> + <xsd:element name="s" type="CT_XStringElement" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional" default="0"/> + </xsd:complexType> + <xsd:element name="singleXmlCells" type="CT_SingleXmlCells"/> + <xsd:complexType name="CT_SingleXmlCells"> + <xsd:sequence> + <xsd:element name="singleXmlCell" type="CT_SingleXmlCell" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SingleXmlCell"> + <xsd:sequence> + <xsd:element name="xmlCellPr" type="CT_XmlCellPr" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="r" type="ST_CellRef" use="required"/> + <xsd:attribute name="connectionId" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_XmlCellPr"> + <xsd:sequence> + <xsd:element name="xmlPr" type="CT_XmlPr" minOccurs="1" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="uniqueName" type="s:ST_Xstring" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_XmlPr"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="mapId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="xpath" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="xmlDataType" type="ST_XmlDataType" use="required"/> + </xsd:complexType> + <xsd:element name="styleSheet" type="CT_Stylesheet"/> + <xsd:complexType name="CT_Stylesheet"> + <xsd:sequence> + <xsd:element name="numFmts" type="CT_NumFmts" minOccurs="0" maxOccurs="1"/> + <xsd:element name="fonts" type="CT_Fonts" minOccurs="0" maxOccurs="1"/> + <xsd:element name="fills" type="CT_Fills" minOccurs="0" maxOccurs="1"/> + <xsd:element name="borders" type="CT_Borders" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cellStyleXfs" type="CT_CellStyleXfs" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cellXfs" type="CT_CellXfs" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cellStyles" type="CT_CellStyles" minOccurs="0" maxOccurs="1"/> + <xsd:element name="dxfs" type="CT_Dxfs" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tableStyles" type="CT_TableStyles" minOccurs="0" maxOccurs="1"/> + <xsd:element name="colors" type="CT_Colors" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CellAlignment"> + <xsd:attribute name="horizontal" type="ST_HorizontalAlignment" use="optional"/> + <xsd:attribute name="vertical" type="ST_VerticalAlignment" default="bottom" use="optional"/> + <xsd:attribute name="textRotation" type="ST_TextRotation" use="optional"/> + <xsd:attribute name="wrapText" type="xsd:boolean" use="optional"/> + <xsd:attribute name="indent" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="relativeIndent" type="xsd:int" use="optional"/> + <xsd:attribute name="justifyLastLine" type="xsd:boolean" use="optional"/> + <xsd:attribute name="shrinkToFit" type="xsd:boolean" use="optional"/> + <xsd:attribute name="readingOrder" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_TextRotation"> + <xsd:union> + <xsd:simpleType> + <xsd:restriction base="xsd:nonNegativeInteger"> + <xsd:maxInclusive value="180"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType> + <xsd:restriction base="xsd:nonNegativeInteger"> + <xsd:enumeration value="255"/> + </xsd:restriction> + </xsd:simpleType> + </xsd:union> + </xsd:simpleType> + <xsd:simpleType name="ST_BorderStyle"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="thin"/> + <xsd:enumeration value="medium"/> + <xsd:enumeration value="dashed"/> + <xsd:enumeration value="dotted"/> + <xsd:enumeration value="thick"/> + <xsd:enumeration value="double"/> + <xsd:enumeration value="hair"/> + <xsd:enumeration value="mediumDashed"/> + <xsd:enumeration value="dashDot"/> + <xsd:enumeration value="mediumDashDot"/> + <xsd:enumeration value="dashDotDot"/> + <xsd:enumeration value="mediumDashDotDot"/> + <xsd:enumeration value="slantDashDot"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Borders"> + <xsd:sequence> + <xsd:element name="border" type="CT_Border" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Border"> + <xsd:sequence> + <xsd:element name="start" type="CT_BorderPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="end" type="CT_BorderPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="left" type="CT_BorderPr" minOccurs="0"/> + <xsd:element name="right" type="CT_BorderPr" minOccurs="0"/> + <xsd:element name="top" type="CT_BorderPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bottom" type="CT_BorderPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="diagonal" type="CT_BorderPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="vertical" type="CT_BorderPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="horizontal" type="CT_BorderPr" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="diagonalUp" type="xsd:boolean" use="optional"/> + <xsd:attribute name="diagonalDown" type="xsd:boolean" use="optional"/> + <xsd:attribute name="outline" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_BorderPr"> + <xsd:sequence> + <xsd:element name="color" type="CT_Color" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="style" type="ST_BorderStyle" use="optional" default="none"/> + </xsd:complexType> + <xsd:complexType name="CT_CellProtection"> + <xsd:attribute name="locked" type="xsd:boolean" use="optional"/> + <xsd:attribute name="hidden" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Fonts"> + <xsd:sequence> + <xsd:element name="font" type="CT_Font" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Fills"> + <xsd:sequence> + <xsd:element name="fill" type="CT_Fill" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Fill"> + <xsd:choice minOccurs="1" maxOccurs="1"> + <xsd:element name="patternFill" type="CT_PatternFill" minOccurs="0" maxOccurs="1"/> + <xsd:element name="gradientFill" type="CT_GradientFill" minOccurs="0" maxOccurs="1"/> + </xsd:choice> + </xsd:complexType> + <xsd:complexType name="CT_PatternFill"> + <xsd:sequence> + <xsd:element name="fgColor" type="CT_Color" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bgColor" type="CT_Color" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="patternType" type="ST_PatternType" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Color"> + <xsd:attribute name="auto" type="xsd:boolean" use="optional"/> + <xsd:attribute name="indexed" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="rgb" type="ST_UnsignedIntHex" use="optional"/> + <xsd:attribute name="theme" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="tint" type="xsd:double" use="optional" default="0.0"/> + </xsd:complexType> + <xsd:simpleType name="ST_PatternType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="solid"/> + <xsd:enumeration value="mediumGray"/> + <xsd:enumeration value="darkGray"/> + <xsd:enumeration value="lightGray"/> + <xsd:enumeration value="darkHorizontal"/> + <xsd:enumeration value="darkVertical"/> + <xsd:enumeration value="darkDown"/> + <xsd:enumeration value="darkUp"/> + <xsd:enumeration value="darkGrid"/> + <xsd:enumeration value="darkTrellis"/> + <xsd:enumeration value="lightHorizontal"/> + <xsd:enumeration value="lightVertical"/> + <xsd:enumeration value="lightDown"/> + <xsd:enumeration value="lightUp"/> + <xsd:enumeration value="lightGrid"/> + <xsd:enumeration value="lightTrellis"/> + <xsd:enumeration value="gray125"/> + <xsd:enumeration value="gray0625"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_GradientFill"> + <xsd:sequence> + <xsd:element name="stop" type="CT_GradientStop" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="type" type="ST_GradientType" use="optional" default="linear"/> + <xsd:attribute name="degree" type="xsd:double" use="optional" default="0"/> + <xsd:attribute name="left" type="xsd:double" use="optional" default="0"/> + <xsd:attribute name="right" type="xsd:double" use="optional" default="0"/> + <xsd:attribute name="top" type="xsd:double" use="optional" default="0"/> + <xsd:attribute name="bottom" type="xsd:double" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_GradientStop"> + <xsd:sequence> + <xsd:element name="color" type="CT_Color" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="position" type="xsd:double" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_GradientType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="linear"/> + <xsd:enumeration value="path"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_HorizontalAlignment"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="general"/> + <xsd:enumeration value="left"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="right"/> + <xsd:enumeration value="fill"/> + <xsd:enumeration value="justify"/> + <xsd:enumeration value="centerContinuous"/> + <xsd:enumeration value="distributed"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_VerticalAlignment"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="top"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="bottom"/> + <xsd:enumeration value="justify"/> + <xsd:enumeration value="distributed"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_NumFmts"> + <xsd:sequence> + <xsd:element name="numFmt" type="CT_NumFmt" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_NumFmt"> + <xsd:attribute name="numFmtId" type="ST_NumFmtId" use="required"/> + <xsd:attribute name="formatCode" type="s:ST_Xstring" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CellStyleXfs"> + <xsd:sequence> + <xsd:element name="xf" type="CT_Xf" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_CellXfs"> + <xsd:sequence> + <xsd:element name="xf" type="CT_Xf" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Xf"> + <xsd:sequence> + <xsd:element name="alignment" type="CT_CellAlignment" minOccurs="0" maxOccurs="1"/> + <xsd:element name="protection" type="CT_CellProtection" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="numFmtId" type="ST_NumFmtId" use="optional"/> + <xsd:attribute name="fontId" type="ST_FontId" use="optional"/> + <xsd:attribute name="fillId" type="ST_FillId" use="optional"/> + <xsd:attribute name="borderId" type="ST_BorderId" use="optional"/> + <xsd:attribute name="xfId" type="ST_CellStyleXfId" use="optional"/> + <xsd:attribute name="quotePrefix" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="pivotButton" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="applyNumberFormat" type="xsd:boolean" use="optional"/> + <xsd:attribute name="applyFont" type="xsd:boolean" use="optional"/> + <xsd:attribute name="applyFill" type="xsd:boolean" use="optional"/> + <xsd:attribute name="applyBorder" type="xsd:boolean" use="optional"/> + <xsd:attribute name="applyAlignment" type="xsd:boolean" use="optional"/> + <xsd:attribute name="applyProtection" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_CellStyles"> + <xsd:sequence> + <xsd:element name="cellStyle" type="CT_CellStyle" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_CellStyle"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="name" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="xfId" type="ST_CellStyleXfId" use="required"/> + <xsd:attribute name="builtinId" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="iLevel" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="hidden" type="xsd:boolean" use="optional"/> + <xsd:attribute name="customBuiltin" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Dxfs"> + <xsd:sequence> + <xsd:element name="dxf" type="CT_Dxf" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Dxf"> + <xsd:sequence> + <xsd:element name="font" type="CT_Font" minOccurs="0" maxOccurs="1"/> + <xsd:element name="numFmt" type="CT_NumFmt" minOccurs="0" maxOccurs="1"/> + <xsd:element name="fill" type="CT_Fill" minOccurs="0" maxOccurs="1"/> + <xsd:element name="alignment" type="CT_CellAlignment" minOccurs="0" maxOccurs="1"/> + <xsd:element name="border" type="CT_Border" minOccurs="0" maxOccurs="1"/> + <xsd:element name="protection" type="CT_CellProtection" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_NumFmtId"> + <xsd:restriction base="xsd:unsignedInt"/> + </xsd:simpleType> + <xsd:simpleType name="ST_FontId"> + <xsd:restriction base="xsd:unsignedInt"/> + </xsd:simpleType> + <xsd:simpleType name="ST_FillId"> + <xsd:restriction base="xsd:unsignedInt"/> + </xsd:simpleType> + <xsd:simpleType name="ST_BorderId"> + <xsd:restriction base="xsd:unsignedInt"/> + </xsd:simpleType> + <xsd:simpleType name="ST_CellStyleXfId"> + <xsd:restriction base="xsd:unsignedInt"/> + </xsd:simpleType> + <xsd:simpleType name="ST_DxfId"> + <xsd:restriction base="xsd:unsignedInt"/> + </xsd:simpleType> + <xsd:complexType name="CT_Colors"> + <xsd:sequence> + <xsd:element name="indexedColors" type="CT_IndexedColors" minOccurs="0" maxOccurs="1"/> + <xsd:element name="mruColors" type="CT_MRUColors" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_IndexedColors"> + <xsd:sequence> + <xsd:element name="rgbColor" type="CT_RgbColor" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_MRUColors"> + <xsd:sequence> + <xsd:element name="color" type="CT_Color" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_RgbColor"> + <xsd:attribute name="rgb" type="ST_UnsignedIntHex" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TableStyles"> + <xsd:sequence> + <xsd:element name="tableStyle" type="CT_TableStyle" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="defaultTableStyle" type="xsd:string" use="optional"/> + <xsd:attribute name="defaultPivotStyle" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TableStyle"> + <xsd:sequence> + <xsd:element name="tableStyleElement" type="CT_TableStyleElement" minOccurs="0" + maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required"/> + <xsd:attribute name="pivot" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="table" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TableStyleElement"> + <xsd:attribute name="type" type="ST_TableStyleType" use="required"/> + <xsd:attribute name="size" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute name="dxfId" type="ST_DxfId" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_TableStyleType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="wholeTable"/> + <xsd:enumeration value="headerRow"/> + <xsd:enumeration value="totalRow"/> + <xsd:enumeration value="firstColumn"/> + <xsd:enumeration value="lastColumn"/> + <xsd:enumeration value="firstRowStripe"/> + <xsd:enumeration value="secondRowStripe"/> + <xsd:enumeration value="firstColumnStripe"/> + <xsd:enumeration value="secondColumnStripe"/> + <xsd:enumeration value="firstHeaderCell"/> + <xsd:enumeration value="lastHeaderCell"/> + <xsd:enumeration value="firstTotalCell"/> + <xsd:enumeration value="lastTotalCell"/> + <xsd:enumeration value="firstSubtotalColumn"/> + <xsd:enumeration value="secondSubtotalColumn"/> + <xsd:enumeration value="thirdSubtotalColumn"/> + <xsd:enumeration value="firstSubtotalRow"/> + <xsd:enumeration value="secondSubtotalRow"/> + <xsd:enumeration value="thirdSubtotalRow"/> + <xsd:enumeration value="blankRow"/> + <xsd:enumeration value="firstColumnSubheading"/> + <xsd:enumeration value="secondColumnSubheading"/> + <xsd:enumeration value="thirdColumnSubheading"/> + <xsd:enumeration value="firstRowSubheading"/> + <xsd:enumeration value="secondRowSubheading"/> + <xsd:enumeration value="thirdRowSubheading"/> + <xsd:enumeration value="pageFieldLabels"/> + <xsd:enumeration value="pageFieldValues"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_BooleanProperty"> + <xsd:attribute name="val" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:complexType name="CT_FontSize"> + <xsd:attribute name="val" type="xsd:double" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_IntProperty"> + <xsd:attribute name="val" type="xsd:int" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_FontName"> + <xsd:attribute name="val" type="s:ST_Xstring" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_VerticalAlignFontProperty"> + <xsd:attribute name="val" type="s:ST_VerticalAlignRun" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_FontScheme"> + <xsd:attribute name="val" type="ST_FontScheme" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_FontScheme"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="major"/> + <xsd:enumeration value="minor"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_UnderlineProperty"> + <xsd:attribute name="val" type="ST_UnderlineValues" use="optional" default="single"/> + </xsd:complexType> + <xsd:simpleType name="ST_UnderlineValues"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="single"/> + <xsd:enumeration value="double"/> + <xsd:enumeration value="singleAccounting"/> + <xsd:enumeration value="doubleAccounting"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Font"> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="name" type="CT_FontName" minOccurs="0" maxOccurs="1"/> + <xsd:element name="charset" type="CT_IntProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="family" type="CT_FontFamily" minOccurs="0" maxOccurs="1"/> + <xsd:element name="b" type="CT_BooleanProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="i" type="CT_BooleanProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="strike" type="CT_BooleanProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="outline" type="CT_BooleanProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="shadow" type="CT_BooleanProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="condense" type="CT_BooleanProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extend" type="CT_BooleanProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="color" type="CT_Color" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sz" type="CT_FontSize" minOccurs="0" maxOccurs="1"/> + <xsd:element name="u" type="CT_UnderlineProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="vertAlign" type="CT_VerticalAlignFontProperty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="scheme" type="CT_FontScheme" minOccurs="0" maxOccurs="1"/> + </xsd:choice> + </xsd:complexType> + <xsd:complexType name="CT_FontFamily"> + <xsd:attribute name="val" type="ST_FontFamily" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_FontFamily"> + <xsd:restriction base="xsd:integer"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="14"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:attributeGroup name="AG_AutoFormat"> + <xsd:attribute name="autoFormatId" type="xsd:unsignedInt"/> + <xsd:attribute name="applyNumberFormats" type="xsd:boolean"/> + <xsd:attribute name="applyBorderFormats" type="xsd:boolean"/> + <xsd:attribute name="applyFontFormats" type="xsd:boolean"/> + <xsd:attribute name="applyPatternFormats" type="xsd:boolean"/> + <xsd:attribute name="applyAlignmentFormats" type="xsd:boolean"/> + <xsd:attribute name="applyWidthHeightFormats" type="xsd:boolean"/> + </xsd:attributeGroup> + <xsd:element name="externalLink" type="CT_ExternalLink"/> + <xsd:complexType name="CT_ExternalLink"> + <xsd:sequence> + <xsd:choice> + <xsd:element name="externalBook" type="CT_ExternalBook" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ddeLink" type="CT_DdeLink" minOccurs="0" maxOccurs="1"/> + <xsd:element name="oleLink" type="CT_OleLink" minOccurs="0" maxOccurs="1"/> + </xsd:choice> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ExternalBook"> + <xsd:sequence> + <xsd:element name="sheetNames" type="CT_ExternalSheetNames" minOccurs="0" maxOccurs="1"/> + <xsd:element name="definedNames" type="CT_ExternalDefinedNames" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sheetDataSet" type="CT_ExternalSheetDataSet" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_ExternalSheetNames"> + <xsd:sequence> + <xsd:element name="sheetName" minOccurs="1" maxOccurs="unbounded" type="CT_ExternalSheetName" + /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ExternalSheetName"> + <xsd:attribute name="val" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:complexType name="CT_ExternalDefinedNames"> + <xsd:sequence> + <xsd:element name="definedName" type="CT_ExternalDefinedName" minOccurs="0" + maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ExternalDefinedName"> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="refersTo" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="sheetId" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_ExternalSheetDataSet"> + <xsd:sequence> + <xsd:element name="sheetData" type="CT_ExternalSheetData" minOccurs="1" maxOccurs="unbounded" + /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ExternalSheetData"> + <xsd:sequence> + <xsd:element name="row" type="CT_ExternalRow" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="sheetId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="refreshError" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_ExternalRow"> + <xsd:sequence> + <xsd:element name="cell" type="CT_ExternalCell" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="r" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_ExternalCell"> + <xsd:sequence> + <xsd:element name="v" type="s:ST_Xstring" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="r" type="ST_CellRef" use="optional"/> + <xsd:attribute name="t" type="ST_CellType" use="optional" default="n"/> + <xsd:attribute name="vm" type="xsd:unsignedInt" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_DdeLink"> + <xsd:sequence> + <xsd:element name="ddeItems" type="CT_DdeItems" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="ddeService" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="ddeTopic" type="s:ST_Xstring" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_DdeItems"> + <xsd:sequence> + <xsd:element name="ddeItem" type="CT_DdeItem" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DdeItem"> + <xsd:sequence> + <xsd:element name="values" type="CT_DdeValues" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="name" type="s:ST_Xstring" default="0"/> + <xsd:attribute name="ole" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="advise" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="preferPic" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_DdeValues"> + <xsd:sequence> + <xsd:element name="value" minOccurs="1" maxOccurs="unbounded" type="CT_DdeValue"/> + </xsd:sequence> + <xsd:attribute name="rows" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute name="cols" type="xsd:unsignedInt" use="optional" default="1"/> + </xsd:complexType> + <xsd:complexType name="CT_DdeValue"> + <xsd:sequence> + <xsd:element name="val" type="s:ST_Xstring" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="t" type="ST_DdeValueType" use="optional" default="n"/> + </xsd:complexType> + <xsd:simpleType name="ST_DdeValueType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="nil"/> + <xsd:enumeration value="b"/> + <xsd:enumeration value="n"/> + <xsd:enumeration value="e"/> + <xsd:enumeration value="str"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_OleLink"> + <xsd:sequence> + <xsd:element name="oleItems" type="CT_OleItems" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute ref="r:id" use="required"/> + <xsd:attribute name="progId" type="s:ST_Xstring" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_OleItems"> + <xsd:sequence> + <xsd:element name="oleItem" type="CT_OleItem" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_OleItem"> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="icon" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="advise" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="preferPic" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:element name="table" type="CT_Table"/> + <xsd:complexType name="CT_Table"> + <xsd:sequence> + <xsd:element name="autoFilter" type="CT_AutoFilter" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sortState" type="CT_SortState" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tableColumns" type="CT_TableColumns" minOccurs="1" maxOccurs="1"/> + <xsd:element name="tableStyleInfo" type="CT_TableStyleInfo" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="name" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="displayName" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="comment" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="ref" type="ST_Ref" use="required"/> + <xsd:attribute name="tableType" type="ST_TableType" use="optional" default="worksheet"/> + <xsd:attribute name="headerRowCount" type="xsd:unsignedInt" use="optional" default="1"/> + <xsd:attribute name="insertRow" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="insertRowShift" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="totalsRowCount" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="totalsRowShown" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="published" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="headerRowDxfId" type="ST_DxfId" use="optional"/> + <xsd:attribute name="dataDxfId" type="ST_DxfId" use="optional"/> + <xsd:attribute name="totalsRowDxfId" type="ST_DxfId" use="optional"/> + <xsd:attribute name="headerRowBorderDxfId" type="ST_DxfId" use="optional"/> + <xsd:attribute name="tableBorderDxfId" type="ST_DxfId" use="optional"/> + <xsd:attribute name="totalsRowBorderDxfId" type="ST_DxfId" use="optional"/> + <xsd:attribute name="headerRowCellStyle" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="dataCellStyle" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="totalsRowCellStyle" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="connectionId" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_TableType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="worksheet"/> + <xsd:enumeration value="xml"/> + <xsd:enumeration value="queryTable"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TableStyleInfo"> + <xsd:attribute name="name" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="showFirstColumn" type="xsd:boolean" use="optional"/> + <xsd:attribute name="showLastColumn" type="xsd:boolean" use="optional"/> + <xsd:attribute name="showRowStripes" type="xsd:boolean" use="optional"/> + <xsd:attribute name="showColumnStripes" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TableColumns"> + <xsd:sequence> + <xsd:element name="tableColumn" type="CT_TableColumn" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TableColumn"> + <xsd:sequence> + <xsd:element name="calculatedColumnFormula" type="CT_TableFormula" minOccurs="0" maxOccurs="1"/> + <xsd:element name="totalsRowFormula" type="CT_TableFormula" minOccurs="0" maxOccurs="1"/> + <xsd:element name="xmlColumnPr" type="CT_XmlColumnPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="uniqueName" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="totalsRowFunction" type="ST_TotalsRowFunction" use="optional" + default="none"/> + <xsd:attribute name="totalsRowLabel" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="queryTableFieldId" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="headerRowDxfId" type="ST_DxfId" use="optional"/> + <xsd:attribute name="dataDxfId" type="ST_DxfId" use="optional"/> + <xsd:attribute name="totalsRowDxfId" type="ST_DxfId" use="optional"/> + <xsd:attribute name="headerRowCellStyle" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="dataCellStyle" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="totalsRowCellStyle" type="s:ST_Xstring" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_TableFormula"> + <xsd:simpleContent> + <xsd:extension base="ST_Formula"> + <xsd:attribute name="array" type="xsd:boolean" default="false"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + <xsd:simpleType name="ST_TotalsRowFunction"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="sum"/> + <xsd:enumeration value="min"/> + <xsd:enumeration value="max"/> + <xsd:enumeration value="average"/> + <xsd:enumeration value="count"/> + <xsd:enumeration value="countNums"/> + <xsd:enumeration value="stdDev"/> + <xsd:enumeration value="var"/> + <xsd:enumeration value="custom"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_XmlColumnPr"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="mapId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="xpath" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="denormalized" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="xmlDataType" type="ST_XmlDataType" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_XmlDataType"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:element name="volTypes" type="CT_VolTypes"/> + <xsd:complexType name="CT_VolTypes"> + <xsd:sequence> + <xsd:element name="volType" type="CT_VolType" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_VolType"> + <xsd:sequence> + <xsd:element name="main" type="CT_VolMain" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="type" type="ST_VolDepType" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_VolMain"> + <xsd:sequence> + <xsd:element name="tp" type="CT_VolTopic" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="first" type="s:ST_Xstring" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_VolTopic"> + <xsd:sequence> + <xsd:element name="v" type="s:ST_Xstring" minOccurs="1" maxOccurs="1"/> + <xsd:element name="stp" type="s:ST_Xstring" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="tr" type="CT_VolTopicRef" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="t" type="ST_VolValueType" use="optional" default="n"/> + </xsd:complexType> + <xsd:complexType name="CT_VolTopicRef"> + <xsd:attribute name="r" type="ST_CellRef" use="required"/> + <xsd:attribute name="s" type="xsd:unsignedInt" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_VolDepType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="realTimeData"/> + <xsd:enumeration value="olapFunctions"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_VolValueType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="b"/> + <xsd:enumeration value="n"/> + <xsd:enumeration value="e"/> + <xsd:enumeration value="s"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:element name="workbook" type="CT_Workbook"/> + <xsd:complexType name="CT_Workbook"> + <xsd:sequence> + <xsd:element name="fileVersion" type="CT_FileVersion" minOccurs="0" maxOccurs="1"/> + <xsd:element name="fileSharing" type="CT_FileSharing" minOccurs="0" maxOccurs="1"/> + <xsd:element name="workbookPr" type="CT_WorkbookPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="workbookProtection" type="CT_WorkbookProtection" minOccurs="0" + maxOccurs="1"/> + <xsd:element name="bookViews" type="CT_BookViews" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sheets" type="CT_Sheets" minOccurs="1" maxOccurs="1"/> + <xsd:element name="functionGroups" type="CT_FunctionGroups" minOccurs="0" maxOccurs="1"/> + <xsd:element name="externalReferences" type="CT_ExternalReferences" minOccurs="0" + maxOccurs="1"/> + <xsd:element name="definedNames" type="CT_DefinedNames" minOccurs="0" maxOccurs="1"/> + <xsd:element name="calcPr" type="CT_CalcPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="oleSize" type="CT_OleSize" minOccurs="0" maxOccurs="1"/> + <xsd:element name="customWorkbookViews" type="CT_CustomWorkbookViews" minOccurs="0" + maxOccurs="1"/> + <xsd:element name="pivotCaches" type="CT_PivotCaches" minOccurs="0" maxOccurs="1"/> + <xsd:element name="smartTagPr" type="CT_SmartTagPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="smartTagTypes" type="CT_SmartTagTypes" minOccurs="0" maxOccurs="1"/> + <xsd:element name="webPublishing" type="CT_WebPublishing" minOccurs="0" maxOccurs="1"/> + <xsd:element name="fileRecoveryPr" type="CT_FileRecoveryPr" minOccurs="0" + maxOccurs="unbounded"/> + <xsd:element name="webPublishObjects" type="CT_WebPublishObjects" minOccurs="0" maxOccurs="1"/> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="conformance" type="s:ST_ConformanceClass"/> + </xsd:complexType> + <xsd:complexType name="CT_FileVersion"> + <xsd:attribute name="appName" type="xsd:string" use="optional"/> + <xsd:attribute name="lastEdited" type="xsd:string" use="optional"/> + <xsd:attribute name="lowestEdited" type="xsd:string" use="optional"/> + <xsd:attribute name="rupBuild" type="xsd:string" use="optional"/> + <xsd:attribute name="codeName" type="s:ST_Guid" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_BookViews"> + <xsd:sequence> + <xsd:element name="workbookView" type="CT_BookView" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_BookView"> + <xsd:sequence> + <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="visibility" type="ST_Visibility" use="optional" default="visible"/> + <xsd:attribute name="minimized" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showHorizontalScroll" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="showVerticalScroll" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="showSheetTabs" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="xWindow" type="xsd:int" use="optional"/> + <xsd:attribute name="yWindow" type="xsd:int" use="optional"/> + <xsd:attribute name="windowWidth" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="windowHeight" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="tabRatio" type="xsd:unsignedInt" use="optional" default="600"/> + <xsd:attribute name="firstSheet" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="activeTab" type="xsd:unsignedInt" use="optional" default="0"/> + <xsd:attribute name="autoFilterDateGrouping" type="xsd:boolean" use="optional" default="true"/> + </xsd:complexType> + <xsd:simpleType name="ST_Visibility"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="visible"/> + <xsd:enumeration value="hidden"/> + <xsd:enumeration value="veryHidden"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_CustomWorkbookViews"> + <xsd:sequence> + <xsd:element name="customWorkbookView" minOccurs="1" maxOccurs="unbounded" + type="CT_CustomWorkbookView"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CustomWorkbookView"> + <xsd:sequence> + <xsd:element name="extLst" minOccurs="0" type="CT_ExtensionList"/> + </xsd:sequence> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="guid" type="s:ST_Guid" use="required"/> + <xsd:attribute name="autoUpdate" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="mergeInterval" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="changesSavedWin" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="onlySync" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="personalView" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="includePrintSettings" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="includeHiddenRowCol" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="maximized" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="minimized" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showHorizontalScroll" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="showVerticalScroll" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="showSheetTabs" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="xWindow" type="xsd:int" use="optional" default="0"/> + <xsd:attribute name="yWindow" type="xsd:int" use="optional" default="0"/> + <xsd:attribute name="windowWidth" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="windowHeight" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="tabRatio" type="xsd:unsignedInt" use="optional" default="600"/> + <xsd:attribute name="activeSheetId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="showFormulaBar" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="showStatusbar" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="showComments" type="ST_Comments" use="optional" default="commIndicator"/> + <xsd:attribute name="showObjects" type="ST_Objects" use="optional" default="all"/> + </xsd:complexType> + <xsd:simpleType name="ST_Comments"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="commNone"/> + <xsd:enumeration value="commIndicator"/> + <xsd:enumeration value="commIndAndComment"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Objects"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="all"/> + <xsd:enumeration value="placeholders"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Sheets"> + <xsd:sequence> + <xsd:element name="sheet" type="CT_Sheet" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Sheet"> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="sheetId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="state" type="ST_SheetState" use="optional" default="visible"/> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_SheetState"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="visible"/> + <xsd:enumeration value="hidden"/> + <xsd:enumeration value="veryHidden"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_WorkbookPr"> + <xsd:attribute name="date1904" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showObjects" type="ST_Objects" use="optional" default="all"/> + <xsd:attribute name="showBorderUnselectedTables" type="xsd:boolean" use="optional" + default="true"/> + <xsd:attribute name="filterPrivacy" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="promptedSolutions" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showInkAnnotation" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="backupFile" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="saveExternalLinkValues" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="updateLinks" type="ST_UpdateLinks" use="optional" default="userSet"/> + <xsd:attribute name="codeName" type="xsd:string" use="optional"/> + <xsd:attribute name="hidePivotFieldList" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="showPivotChartFilter" type="xsd:boolean" default="false"/> + <xsd:attribute name="allowRefreshQuery" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="publishItems" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="checkCompatibility" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="autoCompressPictures" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="refreshAllConnections" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="defaultThemeVersion" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_UpdateLinks"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="userSet"/> + <xsd:enumeration value="never"/> + <xsd:enumeration value="always"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SmartTagPr"> + <xsd:attribute name="embed" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="show" type="ST_SmartTagShow" use="optional" default="all"/> + </xsd:complexType> + <xsd:simpleType name="ST_SmartTagShow"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="all"/> + <xsd:enumeration value="none"/> + <xsd:enumeration value="noIndicator"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SmartTagTypes"> + <xsd:sequence> + <xsd:element name="smartTagType" type="CT_SmartTagType" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SmartTagType"> + <xsd:attribute name="namespaceUri" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="name" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="url" type="s:ST_Xstring" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_FileRecoveryPr"> + <xsd:attribute name="autoRecover" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="crashSave" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="dataExtractLoad" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="repairLoad" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> + <xsd:complexType name="CT_CalcPr"> + <xsd:attribute name="calcId" type="xsd:unsignedInt"/> + <xsd:attribute name="calcMode" type="ST_CalcMode" use="optional" default="auto"/> + <xsd:attribute name="fullCalcOnLoad" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="refMode" type="ST_RefMode" use="optional" default="A1"/> + <xsd:attribute name="iterate" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="iterateCount" type="xsd:unsignedInt" use="optional" default="100"/> + <xsd:attribute name="iterateDelta" type="xsd:double" use="optional" default="0.001"/> + <xsd:attribute name="fullPrecision" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="calcCompleted" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="calcOnSave" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="concurrentCalc" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="concurrentManualCount" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="forceFullCalc" type="xsd:boolean" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_CalcMode"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="manual"/> + <xsd:enumeration value="auto"/> + <xsd:enumeration value="autoNoTable"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_RefMode"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="A1"/> + <xsd:enumeration value="R1C1"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_DefinedNames"> + <xsd:sequence> + <xsd:element name="definedName" type="CT_DefinedName" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DefinedName"> + <xsd:simpleContent> + <xsd:extension base="ST_Formula"> + <xsd:attribute name="name" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="comment" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="customMenu" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="description" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="help" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="statusBar" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="localSheetId" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="hidden" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="function" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="vbProcedure" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="xlm" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="functionGroupId" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="shortcutKey" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="publishToServer" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="workbookParameter" type="xsd:boolean" use="optional" default="false"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + <xsd:complexType name="CT_ExternalReferences"> + <xsd:sequence> + <xsd:element name="externalReference" type="CT_ExternalReference" minOccurs="1" + maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ExternalReference"> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SheetBackgroundPicture"> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_PivotCaches"> + <xsd:sequence> + <xsd:element name="pivotCache" type="CT_PivotCache" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PivotCache"> + <xsd:attribute name="cacheId" type="xsd:unsignedInt" use="required"/> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_FileSharing"> + <xsd:attribute name="readOnlyRecommended" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="userName" type="s:ST_Xstring"/> + <xsd:attribute name="reservationPassword" type="ST_UnsignedShortHex"/> + <xsd:attribute name="algorithmName" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="hashValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="saltValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="spinCount" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_OleSize"> + <xsd:attribute name="ref" type="ST_Ref" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_WorkbookProtection"> + <xsd:attribute name="workbookPassword" type="ST_UnsignedShortHex" use="optional"/> + <xsd:attribute name="workbookPasswordCharacterSet" type="xsd:string" use="optional"/> + <xsd:attribute name="revisionsPassword" type="ST_UnsignedShortHex" use="optional"/> + <xsd:attribute name="revisionsPasswordCharacterSet" type="xsd:string" use="optional"/> + <xsd:attribute name="lockStructure" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="lockWindows" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="lockRevision" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="revisionsAlgorithmName" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="revisionsHashValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="revisionsSaltValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="revisionsSpinCount" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="workbookAlgorithmName" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="workbookHashValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="workbookSaltValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="workbookSpinCount" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_WebPublishing"> + <xsd:attribute name="css" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="thicket" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="longFileNames" type="xsd:boolean" use="optional" default="true"/> + <xsd:attribute name="vml" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="allowPng" type="xsd:boolean" use="optional" default="false"/> + <xsd:attribute name="targetScreenSize" type="ST_TargetScreenSize" use="optional" + default="800x600"/> + <xsd:attribute name="dpi" type="xsd:unsignedInt" use="optional" default="96"/> + <xsd:attribute name="codePage" type="xsd:unsignedInt" use="optional"/> + <xsd:attribute name="characterSet" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_TargetScreenSize"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="544x376"/> + <xsd:enumeration value="640x480"/> + <xsd:enumeration value="720x512"/> + <xsd:enumeration value="800x600"/> + <xsd:enumeration value="1024x768"/> + <xsd:enumeration value="1152x882"/> + <xsd:enumeration value="1152x900"/> + <xsd:enumeration value="1280x1024"/> + <xsd:enumeration value="1600x1200"/> + <xsd:enumeration value="1800x1440"/> + <xsd:enumeration value="1920x1200"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_FunctionGroups"> + <xsd:sequence maxOccurs="unbounded"> + <xsd:element name="functionGroup" type="CT_FunctionGroup" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="builtInGroupCount" type="xsd:unsignedInt" default="16" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_FunctionGroup"> + <xsd:attribute name="name" type="s:ST_Xstring"/> + </xsd:complexType> + <xsd:complexType name="CT_WebPublishObjects"> + <xsd:sequence> + <xsd:element name="webPublishObject" type="CT_WebPublishObject" minOccurs="1" + maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="count" type="xsd:unsignedInt" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_WebPublishObject"> + <xsd:attribute name="id" type="xsd:unsignedInt" use="required"/> + <xsd:attribute name="divId" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="sourceObject" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="destinationFile" type="s:ST_Xstring" use="required"/> + <xsd:attribute name="title" type="s:ST_Xstring" use="optional"/> + <xsd:attribute name="autoRepublish" type="xsd:boolean" use="optional" default="false"/> + </xsd:complexType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd new file mode 100644 index 0000000..8821dd1 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd @@ -0,0 +1,570 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:schemas-microsoft-com:vml" + xmlns:pvml="urn:schemas-microsoft-com:office:powerpoint" + xmlns:o="urn:schemas-microsoft-com:office:office" + xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" + xmlns:w10="urn:schemas-microsoft-com:office:word" + xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + xmlns:x="urn:schemas-microsoft-com:office:excel" + xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + targetNamespace="urn:schemas-microsoft-com:vml" elementFormDefault="qualified" + attributeFormDefault="unqualified"> + <xsd:import namespace="urn:schemas-microsoft-com:office:office" + schemaLocation="vml-officeDrawing.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" + schemaLocation="wml.xsd"/> + <xsd:import namespace="urn:schemas-microsoft-com:office:word" + schemaLocation="vml-wordprocessingDrawing.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + schemaLocation="shared-relationshipReference.xsd"/> + <xsd:import namespace="urn:schemas-microsoft-com:office:excel" + schemaLocation="vml-spreadsheetDrawing.xsd"/> + <xsd:import namespace="urn:schemas-microsoft-com:office:powerpoint" + schemaLocation="vml-presentationDrawing.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + schemaLocation="shared-commonSimpleTypes.xsd"/> + <xsd:attributeGroup name="AG_Id"> + <xsd:attribute name="id" type="xsd:string" use="optional"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_Style"> + <xsd:attribute name="style" type="xsd:string" use="optional"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_Type"> + <xsd:attribute name="type" type="xsd:string" use="optional"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_Adj"> + <xsd:attribute name="adj" type="xsd:string" use="optional"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_Path"> + <xsd:attribute name="path" type="xsd:string" use="optional"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_Fill"> + <xsd:attribute name="filled" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="fillcolor" type="s:ST_ColorType" use="optional"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_Chromakey"> + <xsd:attribute name="chromakey" type="s:ST_ColorType" use="optional"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_Ext"> + <xsd:attribute name="ext" form="qualified" type="ST_Ext"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_CoreAttributes"> + <xsd:attributeGroup ref="AG_Id"/> + <xsd:attributeGroup ref="AG_Style"/> + <xsd:attribute name="href" type="xsd:string" use="optional"/> + <xsd:attribute name="target" type="xsd:string" use="optional"/> + <xsd:attribute name="class" type="xsd:string" use="optional"/> + <xsd:attribute name="title" type="xsd:string" use="optional"/> + <xsd:attribute name="alt" type="xsd:string" use="optional"/> + <xsd:attribute name="coordsize" type="xsd:string" use="optional"/> + <xsd:attribute name="coordorigin" type="xsd:string" use="optional"/> + <xsd:attribute name="wrapcoords" type="xsd:string" use="optional"/> + <xsd:attribute name="print" type="s:ST_TrueFalse" use="optional"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_ShapeAttributes"> + <xsd:attributeGroup ref="AG_Chromakey"/> + <xsd:attributeGroup ref="AG_Fill"/> + <xsd:attribute name="opacity" type="xsd:string" use="optional"/> + <xsd:attribute name="stroked" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="strokecolor" type="s:ST_ColorType" use="optional"/> + <xsd:attribute name="strokeweight" type="xsd:string" use="optional"/> + <xsd:attribute name="insetpen" type="s:ST_TrueFalse" use="optional"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_OfficeCoreAttributes"> + <xsd:attribute ref="o:spid"/> + <xsd:attribute ref="o:oned"/> + <xsd:attribute ref="o:regroupid"/> + <xsd:attribute ref="o:doubleclicknotify"/> + <xsd:attribute ref="o:button"/> + <xsd:attribute ref="o:userhidden"/> + <xsd:attribute ref="o:bullet"/> + <xsd:attribute ref="o:hr"/> + <xsd:attribute ref="o:hrstd"/> + <xsd:attribute ref="o:hrnoshade"/> + <xsd:attribute ref="o:hrpct"/> + <xsd:attribute ref="o:hralign"/> + <xsd:attribute ref="o:allowincell"/> + <xsd:attribute ref="o:allowoverlap"/> + <xsd:attribute ref="o:userdrawn"/> + <xsd:attribute ref="o:bordertopcolor"/> + <xsd:attribute ref="o:borderleftcolor"/> + <xsd:attribute ref="o:borderbottomcolor"/> + <xsd:attribute ref="o:borderrightcolor"/> + <xsd:attribute ref="o:dgmlayout"/> + <xsd:attribute ref="o:dgmnodekind"/> + <xsd:attribute ref="o:dgmlayoutmru"/> + <xsd:attribute ref="o:insetmode"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_OfficeShapeAttributes"> + <xsd:attribute ref="o:spt"/> + <xsd:attribute ref="o:connectortype"/> + <xsd:attribute ref="o:bwmode"/> + <xsd:attribute ref="o:bwpure"/> + <xsd:attribute ref="o:bwnormal"/> + <xsd:attribute ref="o:forcedash"/> + <xsd:attribute ref="o:oleicon"/> + <xsd:attribute ref="o:ole"/> + <xsd:attribute ref="o:preferrelative"/> + <xsd:attribute ref="o:cliptowrap"/> + <xsd:attribute ref="o:clip"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_AllCoreAttributes"> + <xsd:attributeGroup ref="AG_CoreAttributes"/> + <xsd:attributeGroup ref="AG_OfficeCoreAttributes"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_AllShapeAttributes"> + <xsd:attributeGroup ref="AG_ShapeAttributes"/> + <xsd:attributeGroup ref="AG_OfficeShapeAttributes"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_ImageAttributes"> + <xsd:attribute name="src" type="xsd:string" use="optional"/> + <xsd:attribute name="cropleft" type="xsd:string" use="optional"/> + <xsd:attribute name="croptop" type="xsd:string" use="optional"/> + <xsd:attribute name="cropright" type="xsd:string" use="optional"/> + <xsd:attribute name="cropbottom" type="xsd:string" use="optional"/> + <xsd:attribute name="gain" type="xsd:string" use="optional"/> + <xsd:attribute name="blacklevel" type="xsd:string" use="optional"/> + <xsd:attribute name="gamma" type="xsd:string" use="optional"/> + <xsd:attribute name="grayscale" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="bilevel" type="s:ST_TrueFalse" use="optional"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_StrokeAttributes"> + <xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="weight" type="xsd:string" use="optional"/> + <xsd:attribute name="color" type="s:ST_ColorType" use="optional"/> + <xsd:attribute name="opacity" type="xsd:string" use="optional"/> + <xsd:attribute name="linestyle" type="ST_StrokeLineStyle" use="optional"/> + <xsd:attribute name="miterlimit" type="xsd:decimal" use="optional"/> + <xsd:attribute name="joinstyle" type="ST_StrokeJoinStyle" use="optional"/> + <xsd:attribute name="endcap" type="ST_StrokeEndCap" use="optional"/> + <xsd:attribute name="dashstyle" type="xsd:string" use="optional"/> + <xsd:attribute name="filltype" type="ST_FillType" use="optional"/> + <xsd:attribute name="src" type="xsd:string" use="optional"/> + <xsd:attribute name="imageaspect" type="ST_ImageAspect" use="optional"/> + <xsd:attribute name="imagesize" type="xsd:string" use="optional"/> + <xsd:attribute name="imagealignshape" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="color2" type="s:ST_ColorType" use="optional"/> + <xsd:attribute name="startarrow" type="ST_StrokeArrowType" use="optional"/> + <xsd:attribute name="startarrowwidth" type="ST_StrokeArrowWidth" use="optional"/> + <xsd:attribute name="startarrowlength" type="ST_StrokeArrowLength" use="optional"/> + <xsd:attribute name="endarrow" type="ST_StrokeArrowType" use="optional"/> + <xsd:attribute name="endarrowwidth" type="ST_StrokeArrowWidth" use="optional"/> + <xsd:attribute name="endarrowlength" type="ST_StrokeArrowLength" use="optional"/> + <xsd:attribute ref="o:href"/> + <xsd:attribute ref="o:althref"/> + <xsd:attribute ref="o:title"/> + <xsd:attribute ref="o:forcedash"/> + <xsd:attribute ref="r:id" use="optional"/> + <xsd:attribute name="insetpen" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute ref="o:relid"/> + </xsd:attributeGroup> + <xsd:group name="EG_ShapeElements"> + <xsd:choice> + <xsd:element ref="path"/> + <xsd:element ref="formulas"/> + <xsd:element ref="handles"/> + <xsd:element ref="fill"/> + <xsd:element ref="stroke"/> + <xsd:element ref="shadow"/> + <xsd:element ref="textbox"/> + <xsd:element ref="textpath"/> + <xsd:element ref="imagedata"/> + <xsd:element ref="o:skew"/> + <xsd:element ref="o:extrusion"/> + <xsd:element ref="o:callout"/> + <xsd:element ref="o:lock"/> + <xsd:element ref="o:clippath"/> + <xsd:element ref="o:signatureline"/> + <xsd:element ref="w10:wrap"/> + <xsd:element ref="w10:anchorlock"/> + <xsd:element ref="w10:bordertop"/> + <xsd:element ref="w10:borderbottom"/> + <xsd:element ref="w10:borderleft"/> + <xsd:element ref="w10:borderright"/> + <xsd:element ref="x:ClientData" minOccurs="0"/> + <xsd:element ref="pvml:textdata" minOccurs="0"/> + </xsd:choice> + </xsd:group> + <xsd:element name="shape" type="CT_Shape"/> + <xsd:element name="shapetype" type="CT_Shapetype"/> + <xsd:element name="group" type="CT_Group"/> + <xsd:element name="background" type="CT_Background"/> + <xsd:complexType name="CT_Shape"> + <xsd:choice maxOccurs="unbounded"> + <xsd:group ref="EG_ShapeElements"/> + <xsd:element ref="o:ink"/> + <xsd:element ref="pvml:iscomment"/> + <xsd:element ref="o:equationxml"/> + </xsd:choice> + <xsd:attributeGroup ref="AG_AllCoreAttributes"/> + <xsd:attributeGroup ref="AG_AllShapeAttributes"/> + <xsd:attributeGroup ref="AG_Type"/> + <xsd:attributeGroup ref="AG_Adj"/> + <xsd:attributeGroup ref="AG_Path"/> + <xsd:attribute ref="o:gfxdata"/> + <xsd:attribute name="equationxml" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Shapetype"> + <xsd:sequence> + <xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element ref="o:complex" minOccurs="0"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_AllCoreAttributes"/> + <xsd:attributeGroup ref="AG_AllShapeAttributes"/> + <xsd:attributeGroup ref="AG_Adj"/> + <xsd:attributeGroup ref="AG_Path"/> + <xsd:attribute ref="o:master"/> + </xsd:complexType> + <xsd:complexType name="CT_Group"> + <xsd:choice maxOccurs="unbounded"> + <xsd:group ref="EG_ShapeElements"/> + <xsd:element ref="group"/> + <xsd:element ref="shape"/> + <xsd:element ref="shapetype"/> + <xsd:element ref="arc"/> + <xsd:element ref="curve"/> + <xsd:element ref="image"/> + <xsd:element ref="line"/> + <xsd:element ref="oval"/> + <xsd:element ref="polyline"/> + <xsd:element ref="rect"/> + <xsd:element ref="roundrect"/> + <xsd:element ref="o:diagram"/> + </xsd:choice> + <xsd:attributeGroup ref="AG_AllCoreAttributes"/> + <xsd:attributeGroup ref="AG_Fill"/> + <xsd:attribute name="editas" type="ST_EditAs" use="optional"/> + <xsd:attribute ref="o:tableproperties"/> + <xsd:attribute ref="o:tablelimits"/> + </xsd:complexType> + <xsd:complexType name="CT_Background"> + <xsd:sequence> + <xsd:element ref="fill" minOccurs="0"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_Id"/> + <xsd:attributeGroup ref="AG_Fill"/> + <xsd:attribute ref="o:bwmode"/> + <xsd:attribute ref="o:bwpure"/> + <xsd:attribute ref="o:bwnormal"/> + <xsd:attribute ref="o:targetscreensize"/> + </xsd:complexType> + <xsd:element name="fill" type="CT_Fill"/> + <xsd:element name="formulas" type="CT_Formulas"/> + <xsd:element name="handles" type="CT_Handles"/> + <xsd:element name="imagedata" type="CT_ImageData"/> + <xsd:element name="path" type="CT_Path"/> + <xsd:element name="textbox" type="CT_Textbox"/> + <xsd:element name="shadow" type="CT_Shadow"/> + <xsd:element name="stroke" type="CT_Stroke"/> + <xsd:element name="textpath" type="CT_TextPath"/> + <xsd:complexType name="CT_Fill"> + <xsd:sequence> + <xsd:element ref="o:fill" minOccurs="0"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_Id"/> + <xsd:attribute name="type" type="ST_FillType" use="optional"/> + <xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="color" type="s:ST_ColorType" use="optional"/> + <xsd:attribute name="opacity" type="xsd:string" use="optional"/> + <xsd:attribute name="color2" type="s:ST_ColorType" use="optional"/> + <xsd:attribute name="src" type="xsd:string" use="optional"/> + <xsd:attribute ref="o:href"/> + <xsd:attribute ref="o:althref"/> + <xsd:attribute name="size" type="xsd:string" use="optional"/> + <xsd:attribute name="origin" type="xsd:string" use="optional"/> + <xsd:attribute name="position" type="xsd:string" use="optional"/> + <xsd:attribute name="aspect" type="ST_ImageAspect" use="optional"/> + <xsd:attribute name="colors" type="xsd:string" use="optional"/> + <xsd:attribute name="angle" type="xsd:decimal" use="optional"/> + <xsd:attribute name="alignshape" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="focus" type="xsd:string" use="optional"/> + <xsd:attribute name="focussize" type="xsd:string" use="optional"/> + <xsd:attribute name="focusposition" type="xsd:string" use="optional"/> + <xsd:attribute name="method" type="ST_FillMethod" use="optional"/> + <xsd:attribute ref="o:detectmouseclick"/> + <xsd:attribute ref="o:title"/> + <xsd:attribute ref="o:opacity2"/> + <xsd:attribute name="recolor" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="rotate" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute ref="r:id" use="optional"/> + <xsd:attribute ref="o:relid" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Formulas"> + <xsd:sequence> + <xsd:element name="f" type="CT_F" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_F"> + <xsd:attribute name="eqn" type="xsd:string"/> + </xsd:complexType> + <xsd:complexType name="CT_Handles"> + <xsd:sequence> + <xsd:element name="h" type="CT_H" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_H"> + <xsd:attribute name="position" type="xsd:string"/> + <xsd:attribute name="polar" type="xsd:string"/> + <xsd:attribute name="map" type="xsd:string"/> + <xsd:attribute name="invx" type="s:ST_TrueFalse"/> + <xsd:attribute name="invy" type="s:ST_TrueFalse"/> + <xsd:attribute name="switch" type="s:ST_TrueFalseBlank"/> + <xsd:attribute name="xrange" type="xsd:string"/> + <xsd:attribute name="yrange" type="xsd:string"/> + <xsd:attribute name="radiusrange" type="xsd:string"/> + </xsd:complexType> + <xsd:complexType name="CT_ImageData"> + <xsd:attributeGroup ref="AG_Id"/> + <xsd:attributeGroup ref="AG_ImageAttributes"/> + <xsd:attributeGroup ref="AG_Chromakey"/> + <xsd:attribute name="embosscolor" type="s:ST_ColorType" use="optional"/> + <xsd:attribute name="recolortarget" type="s:ST_ColorType"/> + <xsd:attribute ref="o:href"/> + <xsd:attribute ref="o:althref"/> + <xsd:attribute ref="o:title"/> + <xsd:attribute ref="o:oleid"/> + <xsd:attribute ref="o:detectmouseclick"/> + <xsd:attribute ref="o:movie"/> + <xsd:attribute ref="o:relid"/> + <xsd:attribute ref="r:id"/> + <xsd:attribute ref="r:pict"/> + <xsd:attribute ref="r:href"/> + </xsd:complexType> + <xsd:complexType name="CT_Path"> + <xsd:attributeGroup ref="AG_Id"/> + <xsd:attribute name="v" type="xsd:string" use="optional"/> + <xsd:attribute name="limo" type="xsd:string" use="optional"/> + <xsd:attribute name="textboxrect" type="xsd:string" use="optional"/> + <xsd:attribute name="fillok" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="strokeok" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="shadowok" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="arrowok" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="gradientshapeok" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="textpathok" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="insetpenok" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute ref="o:connecttype"/> + <xsd:attribute ref="o:connectlocs"/> + <xsd:attribute ref="o:connectangles"/> + <xsd:attribute ref="o:extrusionok"/> + </xsd:complexType> + <xsd:complexType name="CT_Shadow"> + <xsd:attributeGroup ref="AG_Id"/> + <xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="type" type="ST_ShadowType" use="optional"/> + <xsd:attribute name="obscured" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="color" type="s:ST_ColorType" use="optional"/> + <xsd:attribute name="opacity" type="xsd:string" use="optional"/> + <xsd:attribute name="offset" type="xsd:string" use="optional"/> + <xsd:attribute name="color2" type="s:ST_ColorType" use="optional"/> + <xsd:attribute name="offset2" type="xsd:string" use="optional"/> + <xsd:attribute name="origin" type="xsd:string" use="optional"/> + <xsd:attribute name="matrix" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Stroke"> + <xsd:sequence> + <xsd:element ref="o:left" minOccurs="0"/> + <xsd:element ref="o:top" minOccurs="0"/> + <xsd:element ref="o:right" minOccurs="0"/> + <xsd:element ref="o:bottom" minOccurs="0"/> + <xsd:element ref="o:column" minOccurs="0"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_Id"/> + <xsd:attributeGroup ref="AG_StrokeAttributes"/> + </xsd:complexType> + <xsd:complexType name="CT_Textbox"> + <xsd:choice> + <xsd:element ref="w:txbxContent" minOccurs="0"/> + <xsd:any namespace="##local" processContents="skip"/> + </xsd:choice> + <xsd:attributeGroup ref="AG_Id"/> + <xsd:attributeGroup ref="AG_Style"/> + <xsd:attribute name="inset" type="xsd:string" use="optional"/> + <xsd:attribute ref="o:singleclick"/> + <xsd:attribute ref="o:insetmode"/> + </xsd:complexType> + <xsd:complexType name="CT_TextPath"> + <xsd:attributeGroup ref="AG_Id"/> + <xsd:attributeGroup ref="AG_Style"/> + <xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="fitshape" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="fitpath" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="trim" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="xscale" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="string" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:element name="arc" type="CT_Arc"/> + <xsd:element name="curve" type="CT_Curve"/> + <xsd:element name="image" type="CT_Image"/> + <xsd:element name="line" type="CT_Line"/> + <xsd:element name="oval" type="CT_Oval"/> + <xsd:element name="polyline" type="CT_PolyLine"/> + <xsd:element name="rect" type="CT_Rect"/> + <xsd:element name="roundrect" type="CT_RoundRect"/> + <xsd:complexType name="CT_Arc"> + <xsd:sequence> + <xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_AllCoreAttributes"/> + <xsd:attributeGroup ref="AG_AllShapeAttributes"/> + <xsd:attribute name="startAngle" type="xsd:decimal" use="optional"/> + <xsd:attribute name="endAngle" type="xsd:decimal" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Curve"> + <xsd:sequence> + <xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_AllCoreAttributes"/> + <xsd:attributeGroup ref="AG_AllShapeAttributes"/> + <xsd:attribute name="from" type="xsd:string" use="optional"/> + <xsd:attribute name="control1" type="xsd:string" use="optional"/> + <xsd:attribute name="control2" type="xsd:string" use="optional"/> + <xsd:attribute name="to" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Image"> + <xsd:sequence> + <xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_AllCoreAttributes"/> + <xsd:attributeGroup ref="AG_AllShapeAttributes"/> + <xsd:attributeGroup ref="AG_ImageAttributes"/> + </xsd:complexType> + <xsd:complexType name="CT_Line"> + <xsd:sequence> + <xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_AllCoreAttributes"/> + <xsd:attributeGroup ref="AG_AllShapeAttributes"/> + <xsd:attribute name="from" type="xsd:string" use="optional"/> + <xsd:attribute name="to" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Oval"> + <xsd:choice maxOccurs="unbounded"> + <xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + <xsd:attributeGroup ref="AG_AllCoreAttributes"/> + <xsd:attributeGroup ref="AG_AllShapeAttributes"/> + </xsd:complexType> + <xsd:complexType name="CT_PolyLine"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:group ref="EG_ShapeElements"/> + <xsd:element ref="o:ink"/> + </xsd:choice> + <xsd:attributeGroup ref="AG_AllCoreAttributes"/> + <xsd:attributeGroup ref="AG_AllShapeAttributes"/> + <xsd:attribute name="points" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Rect"> + <xsd:choice maxOccurs="unbounded"> + <xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + <xsd:attributeGroup ref="AG_AllCoreAttributes"/> + <xsd:attributeGroup ref="AG_AllShapeAttributes"/> + </xsd:complexType> + <xsd:complexType name="CT_RoundRect"> + <xsd:choice maxOccurs="unbounded"> + <xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + <xsd:attributeGroup ref="AG_AllCoreAttributes"/> + <xsd:attributeGroup ref="AG_AllShapeAttributes"/> + <xsd:attribute name="arcsize" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_Ext"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="view"/> + <xsd:enumeration value="edit"/> + <xsd:enumeration value="backwardCompatible"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FillType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="solid"/> + <xsd:enumeration value="gradient"/> + <xsd:enumeration value="gradientRadial"/> + <xsd:enumeration value="tile"/> + <xsd:enumeration value="pattern"/> + <xsd:enumeration value="frame"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FillMethod"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="linear"/> + <xsd:enumeration value="sigma"/> + <xsd:enumeration value="any"/> + <xsd:enumeration value="linear sigma"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ShadowType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="single"/> + <xsd:enumeration value="double"/> + <xsd:enumeration value="emboss"/> + <xsd:enumeration value="perspective"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_StrokeLineStyle"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="single"/> + <xsd:enumeration value="thinThin"/> + <xsd:enumeration value="thinThick"/> + <xsd:enumeration value="thickThin"/> + <xsd:enumeration value="thickBetweenThin"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_StrokeJoinStyle"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="round"/> + <xsd:enumeration value="bevel"/> + <xsd:enumeration value="miter"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_StrokeEndCap"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="flat"/> + <xsd:enumeration value="square"/> + <xsd:enumeration value="round"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_StrokeArrowLength"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="short"/> + <xsd:enumeration value="medium"/> + <xsd:enumeration value="long"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_StrokeArrowWidth"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="narrow"/> + <xsd:enumeration value="medium"/> + <xsd:enumeration value="wide"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_StrokeArrowType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="block"/> + <xsd:enumeration value="classic"/> + <xsd:enumeration value="oval"/> + <xsd:enumeration value="diamond"/> + <xsd:enumeration value="open"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ImageAspect"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="ignore"/> + <xsd:enumeration value="atMost"/> + <xsd:enumeration value="atLeast"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_EditAs"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="canvas"/> + <xsd:enumeration value="orgchart"/> + <xsd:enumeration value="radial"/> + <xsd:enumeration value="cycle"/> + <xsd:enumeration value="stacked"/> + <xsd:enumeration value="venn"/> + <xsd:enumeration value="bullseye"/> + </xsd:restriction> + </xsd:simpleType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd new file mode 100644 index 0000000..ca2575c --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd @@ -0,0 +1,509 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml" + xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + targetNamespace="urn:schemas-microsoft-com:office:office" elementFormDefault="qualified" + attributeFormDefault="unqualified"> + <xsd:import namespace="urn:schemas-microsoft-com:vml" schemaLocation="vml-main.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + schemaLocation="shared-relationshipReference.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + schemaLocation="shared-commonSimpleTypes.xsd"/> + <xsd:attribute name="bwmode" type="ST_BWMode"/> + <xsd:attribute name="bwpure" type="ST_BWMode"/> + <xsd:attribute name="bwnormal" type="ST_BWMode"/> + <xsd:attribute name="targetscreensize" type="ST_ScreenSize"/> + <xsd:attribute name="insetmode" type="ST_InsetMode" default="custom"/> + <xsd:attribute name="spt" type="xsd:float"/> + <xsd:attribute name="wrapcoords" type="xsd:string"/> + <xsd:attribute name="oned" type="s:ST_TrueFalse"/> + <xsd:attribute name="regroupid" type="xsd:integer"/> + <xsd:attribute name="doubleclicknotify" type="s:ST_TrueFalse"/> + <xsd:attribute name="connectortype" type="ST_ConnectorType" default="straight"/> + <xsd:attribute name="button" type="s:ST_TrueFalse"/> + <xsd:attribute name="userhidden" type="s:ST_TrueFalse"/> + <xsd:attribute name="forcedash" type="s:ST_TrueFalse"/> + <xsd:attribute name="oleicon" type="s:ST_TrueFalse"/> + <xsd:attribute name="ole" type="s:ST_TrueFalseBlank"/> + <xsd:attribute name="preferrelative" type="s:ST_TrueFalse"/> + <xsd:attribute name="cliptowrap" type="s:ST_TrueFalse"/> + <xsd:attribute name="clip" type="s:ST_TrueFalse"/> + <xsd:attribute name="bullet" type="s:ST_TrueFalse"/> + <xsd:attribute name="hr" type="s:ST_TrueFalse"/> + <xsd:attribute name="hrstd" type="s:ST_TrueFalse"/> + <xsd:attribute name="hrnoshade" type="s:ST_TrueFalse"/> + <xsd:attribute name="hrpct" type="xsd:float"/> + <xsd:attribute name="hralign" type="ST_HrAlign" default="left"/> + <xsd:attribute name="allowincell" type="s:ST_TrueFalse"/> + <xsd:attribute name="allowoverlap" type="s:ST_TrueFalse"/> + <xsd:attribute name="userdrawn" type="s:ST_TrueFalse"/> + <xsd:attribute name="bordertopcolor" type="xsd:string"/> + <xsd:attribute name="borderleftcolor" type="xsd:string"/> + <xsd:attribute name="borderbottomcolor" type="xsd:string"/> + <xsd:attribute name="borderrightcolor" type="xsd:string"/> + <xsd:attribute name="connecttype" type="ST_ConnectType"/> + <xsd:attribute name="connectlocs" type="xsd:string"/> + <xsd:attribute name="connectangles" type="xsd:string"/> + <xsd:attribute name="master" type="xsd:string"/> + <xsd:attribute name="extrusionok" type="s:ST_TrueFalse"/> + <xsd:attribute name="href" type="xsd:string"/> + <xsd:attribute name="althref" type="xsd:string"/> + <xsd:attribute name="title" type="xsd:string"/> + <xsd:attribute name="singleclick" type="s:ST_TrueFalse"/> + <xsd:attribute name="oleid" type="xsd:float"/> + <xsd:attribute name="detectmouseclick" type="s:ST_TrueFalse"/> + <xsd:attribute name="movie" type="xsd:float"/> + <xsd:attribute name="spid" type="xsd:string"/> + <xsd:attribute name="opacity2" type="xsd:string"/> + <xsd:attribute name="relid" type="r:ST_RelationshipId"/> + <xsd:attribute name="dgmlayout" type="ST_DiagramLayout"/> + <xsd:attribute name="dgmnodekind" type="xsd:integer"/> + <xsd:attribute name="dgmlayoutmru" type="ST_DiagramLayout"/> + <xsd:attribute name="gfxdata" type="xsd:base64Binary"/> + <xsd:attribute name="tableproperties" type="xsd:string"/> + <xsd:attribute name="tablelimits" type="xsd:string"/> + <xsd:element name="shapedefaults" type="CT_ShapeDefaults"/> + <xsd:element name="shapelayout" type="CT_ShapeLayout"/> + <xsd:element name="signatureline" type="CT_SignatureLine"/> + <xsd:element name="ink" type="CT_Ink"/> + <xsd:element name="diagram" type="CT_Diagram"/> + <xsd:element name="equationxml" type="CT_EquationXml"/> + <xsd:complexType name="CT_ShapeDefaults"> + <xsd:all minOccurs="0"> + <xsd:element ref="v:fill" minOccurs="0"/> + <xsd:element ref="v:stroke" minOccurs="0"/> + <xsd:element ref="v:textbox" minOccurs="0"/> + <xsd:element ref="v:shadow" minOccurs="0"/> + <xsd:element ref="skew" minOccurs="0"/> + <xsd:element ref="extrusion" minOccurs="0"/> + <xsd:element ref="callout" minOccurs="0"/> + <xsd:element ref="lock" minOccurs="0"/> + <xsd:element name="colormru" minOccurs="0" type="CT_ColorMru"/> + <xsd:element name="colormenu" minOccurs="0" type="CT_ColorMenu"/> + </xsd:all> + <xsd:attributeGroup ref="v:AG_Ext"/> + <xsd:attribute name="spidmax" type="xsd:integer" use="optional"/> + <xsd:attribute name="style" type="xsd:string" use="optional"/> + <xsd:attribute name="fill" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="fillcolor" type="s:ST_ColorType" use="optional"/> + <xsd:attribute name="stroke" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="strokecolor" type="s:ST_ColorType"/> + <xsd:attribute name="allowincell" form="qualified" type="s:ST_TrueFalse"/> + </xsd:complexType> + <xsd:complexType name="CT_Ink"> + <xsd:sequence/> + <xsd:attribute name="i" type="xsd:string"/> + <xsd:attribute name="annotation" type="s:ST_TrueFalse"/> + <xsd:attribute name="contentType" type="ST_ContentType" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_SignatureLine"> + <xsd:attributeGroup ref="v:AG_Ext"/> + <xsd:attribute name="issignatureline" type="s:ST_TrueFalse"/> + <xsd:attribute name="id" type="s:ST_Guid"/> + <xsd:attribute name="provid" type="s:ST_Guid"/> + <xsd:attribute name="signinginstructionsset" type="s:ST_TrueFalse"/> + <xsd:attribute name="allowcomments" type="s:ST_TrueFalse"/> + <xsd:attribute name="showsigndate" type="s:ST_TrueFalse"/> + <xsd:attribute name="suggestedsigner" type="xsd:string" form="qualified"/> + <xsd:attribute name="suggestedsigner2" type="xsd:string" form="qualified"/> + <xsd:attribute name="suggestedsigneremail" type="xsd:string" form="qualified"/> + <xsd:attribute name="signinginstructions" type="xsd:string"/> + <xsd:attribute name="addlxml" type="xsd:string"/> + <xsd:attribute name="sigprovurl" type="xsd:string"/> + </xsd:complexType> + <xsd:complexType name="CT_ShapeLayout"> + <xsd:all> + <xsd:element name="idmap" type="CT_IdMap" minOccurs="0"/> + <xsd:element name="regrouptable" type="CT_RegroupTable" minOccurs="0"/> + <xsd:element name="rules" type="CT_Rules" minOccurs="0"/> + </xsd:all> + <xsd:attributeGroup ref="v:AG_Ext"/> + </xsd:complexType> + <xsd:complexType name="CT_IdMap"> + <xsd:attributeGroup ref="v:AG_Ext"/> + <xsd:attribute name="data" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_RegroupTable"> + <xsd:sequence> + <xsd:element name="entry" type="CT_Entry" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attributeGroup ref="v:AG_Ext"/> + </xsd:complexType> + <xsd:complexType name="CT_Entry"> + <xsd:attribute name="new" type="xsd:int" use="optional"/> + <xsd:attribute name="old" type="xsd:int" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Rules"> + <xsd:sequence> + <xsd:element name="r" type="CT_R" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attributeGroup ref="v:AG_Ext"/> + </xsd:complexType> + <xsd:complexType name="CT_R"> + <xsd:sequence> + <xsd:element name="proxy" type="CT_Proxy" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:string" use="required"/> + <xsd:attribute name="type" type="ST_RType" use="optional"/> + <xsd:attribute name="how" type="ST_How" use="optional"/> + <xsd:attribute name="idref" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Proxy"> + <xsd:attribute name="start" type="s:ST_TrueFalseBlank" use="optional" default="false"/> + <xsd:attribute name="end" type="s:ST_TrueFalseBlank" use="optional" default="false"/> + <xsd:attribute name="idref" type="xsd:string" use="optional"/> + <xsd:attribute name="connectloc" type="xsd:int" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Diagram"> + <xsd:sequence> + <xsd:element name="relationtable" type="CT_RelationTable" minOccurs="0"/> + </xsd:sequence> + <xsd:attributeGroup ref="v:AG_Ext"/> + <xsd:attribute name="dgmstyle" type="xsd:integer" use="optional"/> + <xsd:attribute name="autoformat" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="reverse" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="autolayout" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="dgmscalex" type="xsd:integer" use="optional"/> + <xsd:attribute name="dgmscaley" type="xsd:integer" use="optional"/> + <xsd:attribute name="dgmfontsize" type="xsd:integer" use="optional"/> + <xsd:attribute name="constrainbounds" type="xsd:string" use="optional"/> + <xsd:attribute name="dgmbasetextscale" type="xsd:integer" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_EquationXml"> + <xsd:sequence> + <xsd:any namespace="##any"/> + </xsd:sequence> + <xsd:attribute name="contentType" type="ST_AlternateMathContentType" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_AlternateMathContentType"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:complexType name="CT_RelationTable"> + <xsd:sequence> + <xsd:element name="rel" type="CT_Relation" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attributeGroup ref="v:AG_Ext"/> + </xsd:complexType> + <xsd:complexType name="CT_Relation"> + <xsd:attributeGroup ref="v:AG_Ext"/> + <xsd:attribute name="idsrc" type="xsd:string" use="optional"/> + <xsd:attribute name="iddest" type="xsd:string" use="optional"/> + <xsd:attribute name="idcntr" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_ColorMru"> + <xsd:attributeGroup ref="v:AG_Ext"/> + <xsd:attribute name="colors" type="xsd:string"/> + </xsd:complexType> + <xsd:complexType name="CT_ColorMenu"> + <xsd:attributeGroup ref="v:AG_Ext"/> + <xsd:attribute name="strokecolor" type="s:ST_ColorType"/> + <xsd:attribute name="fillcolor" type="s:ST_ColorType"/> + <xsd:attribute name="shadowcolor" type="s:ST_ColorType"/> + <xsd:attribute name="extrusioncolor" type="s:ST_ColorType"/> + </xsd:complexType> + <xsd:element name="skew" type="CT_Skew"/> + <xsd:element name="extrusion" type="CT_Extrusion"/> + <xsd:element name="callout" type="CT_Callout"/> + <xsd:element name="lock" type="CT_Lock"/> + <xsd:element name="OLEObject" type="CT_OLEObject"/> + <xsd:element name="complex" type="CT_Complex"/> + <xsd:element name="left" type="CT_StrokeChild"/> + <xsd:element name="top" type="CT_StrokeChild"/> + <xsd:element name="right" type="CT_StrokeChild"/> + <xsd:element name="bottom" type="CT_StrokeChild"/> + <xsd:element name="column" type="CT_StrokeChild"/> + <xsd:element name="clippath" type="CT_ClipPath"/> + <xsd:element name="fill" type="CT_Fill"/> + <xsd:complexType name="CT_Skew"> + <xsd:attributeGroup ref="v:AG_Ext"/> + <xsd:attribute name="id" type="xsd:string" use="optional"/> + <xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="offset" type="xsd:string" use="optional"/> + <xsd:attribute name="origin" type="xsd:string" use="optional"/> + <xsd:attribute name="matrix" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Extrusion"> + <xsd:attributeGroup ref="v:AG_Ext"/> + <xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="type" type="ST_ExtrusionType" default="parallel" use="optional"/> + <xsd:attribute name="render" type="ST_ExtrusionRender" default="solid" use="optional"/> + <xsd:attribute name="viewpointorigin" type="xsd:string" use="optional"/> + <xsd:attribute name="viewpoint" type="xsd:string" use="optional"/> + <xsd:attribute name="plane" type="ST_ExtrusionPlane" default="XY" use="optional"/> + <xsd:attribute name="skewangle" type="xsd:float" use="optional"/> + <xsd:attribute name="skewamt" type="xsd:string" use="optional"/> + <xsd:attribute name="foredepth" type="xsd:string" use="optional"/> + <xsd:attribute name="backdepth" type="xsd:string" use="optional"/> + <xsd:attribute name="orientation" type="xsd:string" use="optional"/> + <xsd:attribute name="orientationangle" type="xsd:float" use="optional"/> + <xsd:attribute name="lockrotationcenter" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="autorotationcenter" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="rotationcenter" type="xsd:string" use="optional"/> + <xsd:attribute name="rotationangle" type="xsd:string" use="optional"/> + <xsd:attribute name="colormode" type="ST_ColorMode" use="optional"/> + <xsd:attribute name="color" type="s:ST_ColorType" use="optional"/> + <xsd:attribute name="shininess" type="xsd:float" use="optional"/> + <xsd:attribute name="specularity" type="xsd:string" use="optional"/> + <xsd:attribute name="diffusity" type="xsd:string" use="optional"/> + <xsd:attribute name="metal" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="edge" type="xsd:string" use="optional"/> + <xsd:attribute name="facet" type="xsd:string" use="optional"/> + <xsd:attribute name="lightface" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="brightness" type="xsd:string" use="optional"/> + <xsd:attribute name="lightposition" type="xsd:string" use="optional"/> + <xsd:attribute name="lightlevel" type="xsd:string" use="optional"/> + <xsd:attribute name="lightharsh" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="lightposition2" type="xsd:string" use="optional"/> + <xsd:attribute name="lightlevel2" type="xsd:string" use="optional"/> + <xsd:attribute name="lightharsh2" type="s:ST_TrueFalse" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Callout"> + <xsd:attributeGroup ref="v:AG_Ext"/> + <xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="type" type="xsd:string" use="optional"/> + <xsd:attribute name="gap" type="xsd:string" use="optional"/> + <xsd:attribute name="angle" type="ST_Angle" use="optional"/> + <xsd:attribute name="dropauto" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="drop" type="ST_CalloutDrop" use="optional"/> + <xsd:attribute name="distance" type="xsd:string" use="optional"/> + <xsd:attribute name="lengthspecified" type="s:ST_TrueFalse" default="f" use="optional"/> + <xsd:attribute name="length" type="xsd:string" use="optional"/> + <xsd:attribute name="accentbar" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="textborder" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="minusx" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="minusy" type="s:ST_TrueFalse" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Lock"> + <xsd:attributeGroup ref="v:AG_Ext"/> + <xsd:attribute name="position" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="selection" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="grouping" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="ungrouping" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="rotation" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="cropping" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="verticies" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="adjusthandles" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="text" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="aspectratio" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="shapetype" type="s:ST_TrueFalse" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_OLEObject"> + <xsd:sequence> + <xsd:element name="LinkType" type="ST_OLELinkType" minOccurs="0"/> + <xsd:element name="LockedField" type="s:ST_TrueFalseBlank" minOccurs="0"/> + <xsd:element name="FieldCodes" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="Type" type="ST_OLEType" use="optional"/> + <xsd:attribute name="ProgID" type="xsd:string" use="optional"/> + <xsd:attribute name="ShapeID" type="xsd:string" use="optional"/> + <xsd:attribute name="DrawAspect" type="ST_OLEDrawAspect" use="optional"/> + <xsd:attribute name="ObjectID" type="xsd:string" use="optional"/> + <xsd:attribute ref="r:id" use="optional"/> + <xsd:attribute name="UpdateMode" type="ST_OLEUpdateMode" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Complex"> + <xsd:attributeGroup ref="v:AG_Ext"/> + </xsd:complexType> + <xsd:complexType name="CT_StrokeChild"> + <xsd:attributeGroup ref="v:AG_Ext"/> + <xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="weight" type="xsd:string" use="optional"/> + <xsd:attribute name="color" type="s:ST_ColorType" use="optional"/> + <xsd:attribute name="color2" type="s:ST_ColorType" use="optional"/> + <xsd:attribute name="opacity" type="xsd:string" use="optional"/> + <xsd:attribute name="linestyle" type="v:ST_StrokeLineStyle" use="optional"/> + <xsd:attribute name="miterlimit" type="xsd:decimal" use="optional"/> + <xsd:attribute name="joinstyle" type="v:ST_StrokeJoinStyle" use="optional"/> + <xsd:attribute name="endcap" type="v:ST_StrokeEndCap" use="optional"/> + <xsd:attribute name="dashstyle" type="xsd:string" use="optional"/> + <xsd:attribute name="insetpen" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="filltype" type="v:ST_FillType" use="optional"/> + <xsd:attribute name="src" type="xsd:string" use="optional"/> + <xsd:attribute name="imageaspect" type="v:ST_ImageAspect" use="optional"/> + <xsd:attribute name="imagesize" type="xsd:string" use="optional"/> + <xsd:attribute name="imagealignshape" type="s:ST_TrueFalse" use="optional"/> + <xsd:attribute name="startarrow" type="v:ST_StrokeArrowType" use="optional"/> + <xsd:attribute name="startarrowwidth" type="v:ST_StrokeArrowWidth" use="optional"/> + <xsd:attribute name="startarrowlength" type="v:ST_StrokeArrowLength" use="optional"/> + <xsd:attribute name="endarrow" type="v:ST_StrokeArrowType" use="optional"/> + <xsd:attribute name="endarrowwidth" type="v:ST_StrokeArrowWidth" use="optional"/> + <xsd:attribute name="endarrowlength" type="v:ST_StrokeArrowLength" use="optional"/> + <xsd:attribute ref="href"/> + <xsd:attribute ref="althref"/> + <xsd:attribute ref="title"/> + <xsd:attribute ref="forcedash"/> + </xsd:complexType> + <xsd:complexType name="CT_ClipPath"> + <xsd:attribute name="v" type="xsd:string" use="required" form="qualified"/> + </xsd:complexType> + <xsd:complexType name="CT_Fill"> + <xsd:attributeGroup ref="v:AG_Ext"/> + <xsd:attribute name="type" type="ST_FillType"/> + </xsd:complexType> + <xsd:simpleType name="ST_RType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="arc"/> + <xsd:enumeration value="callout"/> + <xsd:enumeration value="connector"/> + <xsd:enumeration value="align"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_How"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="top"/> + <xsd:enumeration value="middle"/> + <xsd:enumeration value="bottom"/> + <xsd:enumeration value="left"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="right"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_BWMode"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="color"/> + <xsd:enumeration value="auto"/> + <xsd:enumeration value="grayScale"/> + <xsd:enumeration value="lightGrayscale"/> + <xsd:enumeration value="inverseGray"/> + <xsd:enumeration value="grayOutline"/> + <xsd:enumeration value="highContrast"/> + <xsd:enumeration value="black"/> + <xsd:enumeration value="white"/> + <xsd:enumeration value="hide"/> + <xsd:enumeration value="undrawn"/> + <xsd:enumeration value="blackTextAndLines"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ScreenSize"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="544,376"/> + <xsd:enumeration value="640,480"/> + <xsd:enumeration value="720,512"/> + <xsd:enumeration value="800,600"/> + <xsd:enumeration value="1024,768"/> + <xsd:enumeration value="1152,862"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_InsetMode"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="auto"/> + <xsd:enumeration value="custom"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ColorMode"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="auto"/> + <xsd:enumeration value="custom"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ContentType"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="ST_DiagramLayout"> + <xsd:restriction base="xsd:integer"> + <xsd:enumeration value="0"/> + <xsd:enumeration value="1"/> + <xsd:enumeration value="2"/> + <xsd:enumeration value="3"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ExtrusionType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="perspective"/> + <xsd:enumeration value="parallel"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ExtrusionRender"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="solid"/> + <xsd:enumeration value="wireFrame"/> + <xsd:enumeration value="boundingCube"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ExtrusionPlane"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="XY"/> + <xsd:enumeration value="ZX"/> + <xsd:enumeration value="YZ"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Angle"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="any"/> + <xsd:enumeration value="30"/> + <xsd:enumeration value="45"/> + <xsd:enumeration value="60"/> + <xsd:enumeration value="90"/> + <xsd:enumeration value="auto"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_CalloutDrop"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="ST_CalloutPlacement"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="top"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="bottom"/> + <xsd:enumeration value="user"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ConnectorType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="straight"/> + <xsd:enumeration value="elbow"/> + <xsd:enumeration value="curved"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_HrAlign"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="left"/> + <xsd:enumeration value="right"/> + <xsd:enumeration value="center"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_ConnectType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="rect"/> + <xsd:enumeration value="segments"/> + <xsd:enumeration value="custom"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_OLELinkType"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="ST_OLEType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="Embed"/> + <xsd:enumeration value="Link"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_OLEDrawAspect"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="Content"/> + <xsd:enumeration value="Icon"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_OLEUpdateMode"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="Always"/> + <xsd:enumeration value="OnCall"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FillType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="gradientCenter"/> + <xsd:enumeration value="solid"/> + <xsd:enumeration value="pattern"/> + <xsd:enumeration value="tile"/> + <xsd:enumeration value="frame"/> + <xsd:enumeration value="gradientUnscaled"/> + <xsd:enumeration value="gradientRadial"/> + <xsd:enumeration value="gradient"/> + <xsd:enumeration value="background"/> + </xsd:restriction> + </xsd:simpleType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd new file mode 100644 index 0000000..dd079e6 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="urn:schemas-microsoft-com:office:powerpoint" + targetNamespace="urn:schemas-microsoft-com:office:powerpoint" elementFormDefault="qualified" + attributeFormDefault="unqualified"> + <xsd:element name="iscomment" type="CT_Empty"/> + <xsd:element name="textdata" type="CT_Rel"/> + <xsd:complexType name="CT_Empty"/> + <xsd:complexType name="CT_Rel"> + <xsd:attribute name="id" type="xsd:string"/> + </xsd:complexType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd new file mode 100644 index 0000000..3dd6cf6 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="urn:schemas-microsoft-com:office:excel" + xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + targetNamespace="urn:schemas-microsoft-com:office:excel" elementFormDefault="qualified" + attributeFormDefault="unqualified"> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + schemaLocation="shared-commonSimpleTypes.xsd"/> + <xsd:element name="ClientData" type="CT_ClientData"/> + <xsd:complexType name="CT_ClientData"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="MoveWithCells" type="s:ST_TrueFalseBlank"/> + <xsd:element name="SizeWithCells" type="s:ST_TrueFalseBlank"/> + <xsd:element name="Anchor" type="xsd:string"/> + <xsd:element name="Locked" type="s:ST_TrueFalseBlank"/> + <xsd:element name="DefaultSize" type="s:ST_TrueFalseBlank"/> + <xsd:element name="PrintObject" type="s:ST_TrueFalseBlank"/> + <xsd:element name="Disabled" type="s:ST_TrueFalseBlank"/> + <xsd:element name="AutoFill" type="s:ST_TrueFalseBlank"/> + <xsd:element name="AutoLine" type="s:ST_TrueFalseBlank"/> + <xsd:element name="AutoPict" type="s:ST_TrueFalseBlank"/> + <xsd:element name="FmlaMacro" type="xsd:string"/> + <xsd:element name="TextHAlign" type="xsd:string"/> + <xsd:element name="TextVAlign" type="xsd:string"/> + <xsd:element name="LockText" type="s:ST_TrueFalseBlank"/> + <xsd:element name="JustLastX" type="s:ST_TrueFalseBlank"/> + <xsd:element name="SecretEdit" type="s:ST_TrueFalseBlank"/> + <xsd:element name="Default" type="s:ST_TrueFalseBlank"/> + <xsd:element name="Help" type="s:ST_TrueFalseBlank"/> + <xsd:element name="Cancel" type="s:ST_TrueFalseBlank"/> + <xsd:element name="Dismiss" type="s:ST_TrueFalseBlank"/> + <xsd:element name="Accel" type="xsd:integer"/> + <xsd:element name="Accel2" type="xsd:integer"/> + <xsd:element name="Row" type="xsd:integer"/> + <xsd:element name="Column" type="xsd:integer"/> + <xsd:element name="Visible" type="s:ST_TrueFalseBlank"/> + <xsd:element name="RowHidden" type="s:ST_TrueFalseBlank"/> + <xsd:element name="ColHidden" type="s:ST_TrueFalseBlank"/> + <xsd:element name="VTEdit" type="xsd:integer"/> + <xsd:element name="MultiLine" type="s:ST_TrueFalseBlank"/> + <xsd:element name="VScroll" type="s:ST_TrueFalseBlank"/> + <xsd:element name="ValidIds" type="s:ST_TrueFalseBlank"/> + <xsd:element name="FmlaRange" type="xsd:string"/> + <xsd:element name="WidthMin" type="xsd:integer"/> + <xsd:element name="Sel" type="xsd:integer"/> + <xsd:element name="NoThreeD2" type="s:ST_TrueFalseBlank"/> + <xsd:element name="SelType" type="xsd:string"/> + <xsd:element name="MultiSel" type="xsd:string"/> + <xsd:element name="LCT" type="xsd:string"/> + <xsd:element name="ListItem" type="xsd:string"/> + <xsd:element name="DropStyle" type="xsd:string"/> + <xsd:element name="Colored" type="s:ST_TrueFalseBlank"/> + <xsd:element name="DropLines" type="xsd:integer"/> + <xsd:element name="Checked" type="xsd:integer"/> + <xsd:element name="FmlaLink" type="xsd:string"/> + <xsd:element name="FmlaPict" type="xsd:string"/> + <xsd:element name="NoThreeD" type="s:ST_TrueFalseBlank"/> + <xsd:element name="FirstButton" type="s:ST_TrueFalseBlank"/> + <xsd:element name="FmlaGroup" type="xsd:string"/> + <xsd:element name="Val" type="xsd:integer"/> + <xsd:element name="Min" type="xsd:integer"/> + <xsd:element name="Max" type="xsd:integer"/> + <xsd:element name="Inc" type="xsd:integer"/> + <xsd:element name="Page" type="xsd:integer"/> + <xsd:element name="Horiz" type="s:ST_TrueFalseBlank"/> + <xsd:element name="Dx" type="xsd:integer"/> + <xsd:element name="MapOCX" type="s:ST_TrueFalseBlank"/> + <xsd:element name="CF" type="ST_CF"/> + <xsd:element name="Camera" type="s:ST_TrueFalseBlank"/> + <xsd:element name="RecalcAlways" type="s:ST_TrueFalseBlank"/> + <xsd:element name="AutoScale" type="s:ST_TrueFalseBlank"/> + <xsd:element name="DDE" type="s:ST_TrueFalseBlank"/> + <xsd:element name="UIObj" type="s:ST_TrueFalseBlank"/> + <xsd:element name="ScriptText" type="xsd:string"/> + <xsd:element name="ScriptExtended" type="xsd:string"/> + <xsd:element name="ScriptLanguage" type="xsd:nonNegativeInteger"/> + <xsd:element name="ScriptLocation" type="xsd:nonNegativeInteger"/> + <xsd:element name="FmlaTxbx" type="xsd:string"/> + </xsd:choice> + <xsd:attribute name="ObjectType" type="ST_ObjectType" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_CF"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:simpleType name="ST_ObjectType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="Button"/> + <xsd:enumeration value="Checkbox"/> + <xsd:enumeration value="Dialog"/> + <xsd:enumeration value="Drop"/> + <xsd:enumeration value="Edit"/> + <xsd:enumeration value="GBox"/> + <xsd:enumeration value="Label"/> + <xsd:enumeration value="LineA"/> + <xsd:enumeration value="List"/> + <xsd:enumeration value="Movie"/> + <xsd:enumeration value="Note"/> + <xsd:enumeration value="Pict"/> + <xsd:enumeration value="Radio"/> + <xsd:enumeration value="RectA"/> + <xsd:enumeration value="Scroll"/> + <xsd:enumeration value="Spin"/> + <xsd:enumeration value="Shape"/> + <xsd:enumeration value="Group"/> + <xsd:enumeration value="Rect"/> + </xsd:restriction> + </xsd:simpleType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd new file mode 100644 index 0000000..f1041e3 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="urn:schemas-microsoft-com:office:word" + targetNamespace="urn:schemas-microsoft-com:office:word" elementFormDefault="qualified" + attributeFormDefault="unqualified"> + <xsd:element name="bordertop" type="CT_Border"/> + <xsd:element name="borderleft" type="CT_Border"/> + <xsd:element name="borderright" type="CT_Border"/> + <xsd:element name="borderbottom" type="CT_Border"/> + <xsd:complexType name="CT_Border"> + <xsd:attribute name="type" type="ST_BorderType" use="optional"/> + <xsd:attribute name="width" type="xsd:positiveInteger" use="optional"/> + <xsd:attribute name="shadow" type="ST_BorderShadow" use="optional"/> + </xsd:complexType> + <xsd:element name="wrap" type="CT_Wrap"/> + <xsd:complexType name="CT_Wrap"> + <xsd:attribute name="type" type="ST_WrapType" use="optional"/> + <xsd:attribute name="side" type="ST_WrapSide" use="optional"/> + <xsd:attribute name="anchorx" type="ST_HorizontalAnchor" use="optional"/> + <xsd:attribute name="anchory" type="ST_VerticalAnchor" use="optional"/> + </xsd:complexType> + <xsd:element name="anchorlock" type="CT_AnchorLock"/> + <xsd:complexType name="CT_AnchorLock"/> + <xsd:simpleType name="ST_BorderType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="single"/> + <xsd:enumeration value="thick"/> + <xsd:enumeration value="double"/> + <xsd:enumeration value="hairline"/> + <xsd:enumeration value="dot"/> + <xsd:enumeration value="dash"/> + <xsd:enumeration value="dotDash"/> + <xsd:enumeration value="dashDotDot"/> + <xsd:enumeration value="triple"/> + <xsd:enumeration value="thinThickSmall"/> + <xsd:enumeration value="thickThinSmall"/> + <xsd:enumeration value="thickBetweenThinSmall"/> + <xsd:enumeration value="thinThick"/> + <xsd:enumeration value="thickThin"/> + <xsd:enumeration value="thickBetweenThin"/> + <xsd:enumeration value="thinThickLarge"/> + <xsd:enumeration value="thickThinLarge"/> + <xsd:enumeration value="thickBetweenThinLarge"/> + <xsd:enumeration value="wave"/> + <xsd:enumeration value="doubleWave"/> + <xsd:enumeration value="dashedSmall"/> + <xsd:enumeration value="dashDotStroked"/> + <xsd:enumeration value="threeDEmboss"/> + <xsd:enumeration value="threeDEngrave"/> + <xsd:enumeration value="HTMLOutset"/> + <xsd:enumeration value="HTMLInset"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_BorderShadow"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="t"/> + <xsd:enumeration value="true"/> + <xsd:enumeration value="f"/> + <xsd:enumeration value="false"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_WrapType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="topAndBottom"/> + <xsd:enumeration value="square"/> + <xsd:enumeration value="none"/> + <xsd:enumeration value="tight"/> + <xsd:enumeration value="through"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_WrapSide"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="both"/> + <xsd:enumeration value="left"/> + <xsd:enumeration value="right"/> + <xsd:enumeration value="largest"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_HorizontalAnchor"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="margin"/> + <xsd:enumeration value="page"/> + <xsd:enumeration value="text"/> + <xsd:enumeration value="char"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_VerticalAnchor"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="margin"/> + <xsd:enumeration value="page"/> + <xsd:enumeration value="text"/> + <xsd:enumeration value="line"/> + </xsd:restriction> + </xsd:simpleType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd new file mode 100644 index 0000000..9c5b7a6 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd @@ -0,0 +1,3646 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" + xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main" + xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" + xmlns="http://schemas.openxmlformats.org/wordprocessingml/2006/main" + xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" + targetNamespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main"> + <xsd:import namespace="http://schemas.openxmlformats.org/markup-compatibility/2006" schemaLocation="../mce/mc.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" + schemaLocation="dml-wordprocessingDrawing.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/math" + schemaLocation="shared-math.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships" + schemaLocation="shared-relationshipReference.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" + schemaLocation="shared-commonSimpleTypes.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/schemaLibrary/2006/main" + schemaLocation="shared-customXmlSchemaProperties.xsd"/> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/> + <xsd:complexType name="CT_Empty"/> + <xsd:complexType name="CT_OnOff"> + <xsd:attribute name="val" type="s:ST_OnOff"/> + </xsd:complexType> + <xsd:simpleType name="ST_LongHexNumber"> + <xsd:restriction base="xsd:hexBinary"> + <xsd:length value="4"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_LongHexNumber"> + <xsd:attribute name="val" type="ST_LongHexNumber" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_ShortHexNumber"> + <xsd:restriction base="xsd:hexBinary"> + <xsd:length value="2"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_UcharHexNumber"> + <xsd:restriction base="xsd:hexBinary"> + <xsd:length value="1"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Charset"> + <xsd:attribute name="val" type="ST_UcharHexNumber" use="optional"/> + <xsd:attribute name="characterSet" type="s:ST_String" use="optional" default="ISO-8859-1"/> + </xsd:complexType> + <xsd:simpleType name="ST_DecimalNumberOrPercent"> + <xsd:union memberTypes="ST_UnqualifiedPercentage s:ST_Percentage"/> + </xsd:simpleType> + <xsd:simpleType name="ST_UnqualifiedPercentage"> + <xsd:restriction base="xsd:decimal"/> + </xsd:simpleType> + <xsd:simpleType name="ST_DecimalNumber"> + <xsd:restriction base="xsd:integer"/> + </xsd:simpleType> + <xsd:complexType name="CT_DecimalNumber"> + <xsd:attribute name="val" type="ST_DecimalNumber" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_UnsignedDecimalNumber"> + <xsd:attribute name="val" type="s:ST_UnsignedDecimalNumber" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_DecimalNumberOrPrecent"> + <xsd:attribute name="val" type="ST_DecimalNumberOrPercent" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TwipsMeasure"> + <xsd:attribute name="val" type="s:ST_TwipsMeasure" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_SignedTwipsMeasure"> + <xsd:union memberTypes="xsd:integer s:ST_UniversalMeasure"/> + </xsd:simpleType> + <xsd:complexType name="CT_SignedTwipsMeasure"> + <xsd:attribute name="val" type="ST_SignedTwipsMeasure" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_PixelsMeasure"> + <xsd:restriction base="s:ST_UnsignedDecimalNumber"/> + </xsd:simpleType> + <xsd:complexType name="CT_PixelsMeasure"> + <xsd:attribute name="val" type="ST_PixelsMeasure" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_HpsMeasure"> + <xsd:union memberTypes="s:ST_UnsignedDecimalNumber s:ST_PositiveUniversalMeasure"/> + </xsd:simpleType> + <xsd:complexType name="CT_HpsMeasure"> + <xsd:attribute name="val" type="ST_HpsMeasure" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_SignedHpsMeasure"> + <xsd:union memberTypes="xsd:integer s:ST_UniversalMeasure"/> + </xsd:simpleType> + <xsd:complexType name="CT_SignedHpsMeasure"> + <xsd:attribute name="val" type="ST_SignedHpsMeasure" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_DateTime"> + <xsd:restriction base="xsd:dateTime"/> + </xsd:simpleType> + <xsd:simpleType name="ST_MacroName"> + <xsd:restriction base="xsd:string"> + <xsd:maxLength value="33"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_MacroName"> + <xsd:attribute name="val" use="required" type="ST_MacroName"/> + </xsd:complexType> + <xsd:simpleType name="ST_EighthPointMeasure"> + <xsd:restriction base="s:ST_UnsignedDecimalNumber"/> + </xsd:simpleType> + <xsd:simpleType name="ST_PointMeasure"> + <xsd:restriction base="s:ST_UnsignedDecimalNumber"/> + </xsd:simpleType> + <xsd:complexType name="CT_String"> + <xsd:attribute name="val" type="s:ST_String" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_TextScale"> + <xsd:union memberTypes="ST_TextScalePercent ST_TextScaleDecimal"/> + </xsd:simpleType> + <xsd:simpleType name="ST_TextScalePercent"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="0*(600|([0-5]?[0-9]?[0-9]))%"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TextScaleDecimal"> + <xsd:restriction base="xsd:integer"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="600"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextScale"> + <xsd:attribute name="val" type="ST_TextScale"/> + </xsd:complexType> + <xsd:simpleType name="ST_HighlightColor"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="black"/> + <xsd:enumeration value="blue"/> + <xsd:enumeration value="cyan"/> + <xsd:enumeration value="green"/> + <xsd:enumeration value="magenta"/> + <xsd:enumeration value="red"/> + <xsd:enumeration value="yellow"/> + <xsd:enumeration value="white"/> + <xsd:enumeration value="darkBlue"/> + <xsd:enumeration value="darkCyan"/> + <xsd:enumeration value="darkGreen"/> + <xsd:enumeration value="darkMagenta"/> + <xsd:enumeration value="darkRed"/> + <xsd:enumeration value="darkYellow"/> + <xsd:enumeration value="darkGray"/> + <xsd:enumeration value="lightGray"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Highlight"> + <xsd:attribute name="val" type="ST_HighlightColor" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_HexColorAuto"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="auto"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_HexColor"> + <xsd:union memberTypes="ST_HexColorAuto s:ST_HexColorRGB"/> + </xsd:simpleType> + <xsd:complexType name="CT_Color"> + <xsd:attribute name="val" type="ST_HexColor" use="required"/> + <xsd:attribute name="themeColor" type="ST_ThemeColor" use="optional"/> + <xsd:attribute name="themeTint" type="ST_UcharHexNumber" use="optional"/> + <xsd:attribute name="themeShade" type="ST_UcharHexNumber" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Lang"> + <xsd:attribute name="val" type="s:ST_Lang" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Guid"> + <xsd:attribute name="val" type="s:ST_Guid"/> + </xsd:complexType> + <xsd:simpleType name="ST_Underline"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="single"/> + <xsd:enumeration value="words"/> + <xsd:enumeration value="double"/> + <xsd:enumeration value="thick"/> + <xsd:enumeration value="dotted"/> + <xsd:enumeration value="dottedHeavy"/> + <xsd:enumeration value="dash"/> + <xsd:enumeration value="dashedHeavy"/> + <xsd:enumeration value="dashLong"/> + <xsd:enumeration value="dashLongHeavy"/> + <xsd:enumeration value="dotDash"/> + <xsd:enumeration value="dashDotHeavy"/> + <xsd:enumeration value="dotDotDash"/> + <xsd:enumeration value="dashDotDotHeavy"/> + <xsd:enumeration value="wave"/> + <xsd:enumeration value="wavyHeavy"/> + <xsd:enumeration value="wavyDouble"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Underline"> + <xsd:attribute name="val" type="ST_Underline" use="optional"/> + <xsd:attribute name="color" type="ST_HexColor" use="optional" default="auto"/> + <xsd:attribute name="themeColor" type="ST_ThemeColor" use="optional"/> + <xsd:attribute name="themeTint" type="ST_UcharHexNumber" use="optional"/> + <xsd:attribute name="themeShade" type="ST_UcharHexNumber" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_TextEffect"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="blinkBackground"/> + <xsd:enumeration value="lights"/> + <xsd:enumeration value="antsBlack"/> + <xsd:enumeration value="antsRed"/> + <xsd:enumeration value="shimmer"/> + <xsd:enumeration value="sparkle"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextEffect"> + <xsd:attribute name="val" type="ST_TextEffect" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_Border"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="nil"/> + <xsd:enumeration value="none"/> + <xsd:enumeration value="single"/> + <xsd:enumeration value="thick"/> + <xsd:enumeration value="double"/> + <xsd:enumeration value="dotted"/> + <xsd:enumeration value="dashed"/> + <xsd:enumeration value="dotDash"/> + <xsd:enumeration value="dotDotDash"/> + <xsd:enumeration value="triple"/> + <xsd:enumeration value="thinThickSmallGap"/> + <xsd:enumeration value="thickThinSmallGap"/> + <xsd:enumeration value="thinThickThinSmallGap"/> + <xsd:enumeration value="thinThickMediumGap"/> + <xsd:enumeration value="thickThinMediumGap"/> + <xsd:enumeration value="thinThickThinMediumGap"/> + <xsd:enumeration value="thinThickLargeGap"/> + <xsd:enumeration value="thickThinLargeGap"/> + <xsd:enumeration value="thinThickThinLargeGap"/> + <xsd:enumeration value="wave"/> + <xsd:enumeration value="doubleWave"/> + <xsd:enumeration value="dashSmallGap"/> + <xsd:enumeration value="dashDotStroked"/> + <xsd:enumeration value="threeDEmboss"/> + <xsd:enumeration value="threeDEngrave"/> + <xsd:enumeration value="outset"/> + <xsd:enumeration value="inset"/> + <xsd:enumeration value="apples"/> + <xsd:enumeration value="archedScallops"/> + <xsd:enumeration value="babyPacifier"/> + <xsd:enumeration value="babyRattle"/> + <xsd:enumeration value="balloons3Colors"/> + <xsd:enumeration value="balloonsHotAir"/> + <xsd:enumeration value="basicBlackDashes"/> + <xsd:enumeration value="basicBlackDots"/> + <xsd:enumeration value="basicBlackSquares"/> + <xsd:enumeration value="basicThinLines"/> + <xsd:enumeration value="basicWhiteDashes"/> + <xsd:enumeration value="basicWhiteDots"/> + <xsd:enumeration value="basicWhiteSquares"/> + <xsd:enumeration value="basicWideInline"/> + <xsd:enumeration value="basicWideMidline"/> + <xsd:enumeration value="basicWideOutline"/> + <xsd:enumeration value="bats"/> + <xsd:enumeration value="birds"/> + <xsd:enumeration value="birdsFlight"/> + <xsd:enumeration value="cabins"/> + <xsd:enumeration value="cakeSlice"/> + <xsd:enumeration value="candyCorn"/> + <xsd:enumeration value="celticKnotwork"/> + <xsd:enumeration value="certificateBanner"/> + <xsd:enumeration value="chainLink"/> + <xsd:enumeration value="champagneBottle"/> + <xsd:enumeration value="checkedBarBlack"/> + <xsd:enumeration value="checkedBarColor"/> + <xsd:enumeration value="checkered"/> + <xsd:enumeration value="christmasTree"/> + <xsd:enumeration value="circlesLines"/> + <xsd:enumeration value="circlesRectangles"/> + <xsd:enumeration value="classicalWave"/> + <xsd:enumeration value="clocks"/> + <xsd:enumeration value="compass"/> + <xsd:enumeration value="confetti"/> + <xsd:enumeration value="confettiGrays"/> + <xsd:enumeration value="confettiOutline"/> + <xsd:enumeration value="confettiStreamers"/> + <xsd:enumeration value="confettiWhite"/> + <xsd:enumeration value="cornerTriangles"/> + <xsd:enumeration value="couponCutoutDashes"/> + <xsd:enumeration value="couponCutoutDots"/> + <xsd:enumeration value="crazyMaze"/> + <xsd:enumeration value="creaturesButterfly"/> + <xsd:enumeration value="creaturesFish"/> + <xsd:enumeration value="creaturesInsects"/> + <xsd:enumeration value="creaturesLadyBug"/> + <xsd:enumeration value="crossStitch"/> + <xsd:enumeration value="cup"/> + <xsd:enumeration value="decoArch"/> + <xsd:enumeration value="decoArchColor"/> + <xsd:enumeration value="decoBlocks"/> + <xsd:enumeration value="diamondsGray"/> + <xsd:enumeration value="doubleD"/> + <xsd:enumeration value="doubleDiamonds"/> + <xsd:enumeration value="earth1"/> + <xsd:enumeration value="earth2"/> + <xsd:enumeration value="earth3"/> + <xsd:enumeration value="eclipsingSquares1"/> + <xsd:enumeration value="eclipsingSquares2"/> + <xsd:enumeration value="eggsBlack"/> + <xsd:enumeration value="fans"/> + <xsd:enumeration value="film"/> + <xsd:enumeration value="firecrackers"/> + <xsd:enumeration value="flowersBlockPrint"/> + <xsd:enumeration value="flowersDaisies"/> + <xsd:enumeration value="flowersModern1"/> + <xsd:enumeration value="flowersModern2"/> + <xsd:enumeration value="flowersPansy"/> + <xsd:enumeration value="flowersRedRose"/> + <xsd:enumeration value="flowersRoses"/> + <xsd:enumeration value="flowersTeacup"/> + <xsd:enumeration value="flowersTiny"/> + <xsd:enumeration value="gems"/> + <xsd:enumeration value="gingerbreadMan"/> + <xsd:enumeration value="gradient"/> + <xsd:enumeration value="handmade1"/> + <xsd:enumeration value="handmade2"/> + <xsd:enumeration value="heartBalloon"/> + <xsd:enumeration value="heartGray"/> + <xsd:enumeration value="hearts"/> + <xsd:enumeration value="heebieJeebies"/> + <xsd:enumeration value="holly"/> + <xsd:enumeration value="houseFunky"/> + <xsd:enumeration value="hypnotic"/> + <xsd:enumeration value="iceCreamCones"/> + <xsd:enumeration value="lightBulb"/> + <xsd:enumeration value="lightning1"/> + <xsd:enumeration value="lightning2"/> + <xsd:enumeration value="mapPins"/> + <xsd:enumeration value="mapleLeaf"/> + <xsd:enumeration value="mapleMuffins"/> + <xsd:enumeration value="marquee"/> + <xsd:enumeration value="marqueeToothed"/> + <xsd:enumeration value="moons"/> + <xsd:enumeration value="mosaic"/> + <xsd:enumeration value="musicNotes"/> + <xsd:enumeration value="northwest"/> + <xsd:enumeration value="ovals"/> + <xsd:enumeration value="packages"/> + <xsd:enumeration value="palmsBlack"/> + <xsd:enumeration value="palmsColor"/> + <xsd:enumeration value="paperClips"/> + <xsd:enumeration value="papyrus"/> + <xsd:enumeration value="partyFavor"/> + <xsd:enumeration value="partyGlass"/> + <xsd:enumeration value="pencils"/> + <xsd:enumeration value="people"/> + <xsd:enumeration value="peopleWaving"/> + <xsd:enumeration value="peopleHats"/> + <xsd:enumeration value="poinsettias"/> + <xsd:enumeration value="postageStamp"/> + <xsd:enumeration value="pumpkin1"/> + <xsd:enumeration value="pushPinNote2"/> + <xsd:enumeration value="pushPinNote1"/> + <xsd:enumeration value="pyramids"/> + <xsd:enumeration value="pyramidsAbove"/> + <xsd:enumeration value="quadrants"/> + <xsd:enumeration value="rings"/> + <xsd:enumeration value="safari"/> + <xsd:enumeration value="sawtooth"/> + <xsd:enumeration value="sawtoothGray"/> + <xsd:enumeration value="scaredCat"/> + <xsd:enumeration value="seattle"/> + <xsd:enumeration value="shadowedSquares"/> + <xsd:enumeration value="sharksTeeth"/> + <xsd:enumeration value="shorebirdTracks"/> + <xsd:enumeration value="skyrocket"/> + <xsd:enumeration value="snowflakeFancy"/> + <xsd:enumeration value="snowflakes"/> + <xsd:enumeration value="sombrero"/> + <xsd:enumeration value="southwest"/> + <xsd:enumeration value="stars"/> + <xsd:enumeration value="starsTop"/> + <xsd:enumeration value="stars3d"/> + <xsd:enumeration value="starsBlack"/> + <xsd:enumeration value="starsShadowed"/> + <xsd:enumeration value="sun"/> + <xsd:enumeration value="swirligig"/> + <xsd:enumeration value="tornPaper"/> + <xsd:enumeration value="tornPaperBlack"/> + <xsd:enumeration value="trees"/> + <xsd:enumeration value="triangleParty"/> + <xsd:enumeration value="triangles"/> + <xsd:enumeration value="triangle1"/> + <xsd:enumeration value="triangle2"/> + <xsd:enumeration value="triangleCircle1"/> + <xsd:enumeration value="triangleCircle2"/> + <xsd:enumeration value="shapes1"/> + <xsd:enumeration value="shapes2"/> + <xsd:enumeration value="twistedLines1"/> + <xsd:enumeration value="twistedLines2"/> + <xsd:enumeration value="vine"/> + <xsd:enumeration value="waveline"/> + <xsd:enumeration value="weavingAngles"/> + <xsd:enumeration value="weavingBraid"/> + <xsd:enumeration value="weavingRibbon"/> + <xsd:enumeration value="weavingStrips"/> + <xsd:enumeration value="whiteFlowers"/> + <xsd:enumeration value="woodwork"/> + <xsd:enumeration value="xIllusions"/> + <xsd:enumeration value="zanyTriangles"/> + <xsd:enumeration value="zigZag"/> + <xsd:enumeration value="zigZagStitch"/> + <xsd:enumeration value="custom"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Border"> + <xsd:attribute name="val" type="ST_Border" use="required"/> + <xsd:attribute name="color" type="ST_HexColor" use="optional" default="auto"/> + <xsd:attribute name="themeColor" type="ST_ThemeColor" use="optional"/> + <xsd:attribute name="themeTint" type="ST_UcharHexNumber" use="optional"/> + <xsd:attribute name="themeShade" type="ST_UcharHexNumber" use="optional"/> + <xsd:attribute name="sz" type="ST_EighthPointMeasure" use="optional"/> + <xsd:attribute name="space" type="ST_PointMeasure" use="optional" default="0"/> + <xsd:attribute name="shadow" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="frame" type="s:ST_OnOff" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_Shd"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="nil"/> + <xsd:enumeration value="clear"/> + <xsd:enumeration value="solid"/> + <xsd:enumeration value="horzStripe"/> + <xsd:enumeration value="vertStripe"/> + <xsd:enumeration value="reverseDiagStripe"/> + <xsd:enumeration value="diagStripe"/> + <xsd:enumeration value="horzCross"/> + <xsd:enumeration value="diagCross"/> + <xsd:enumeration value="thinHorzStripe"/> + <xsd:enumeration value="thinVertStripe"/> + <xsd:enumeration value="thinReverseDiagStripe"/> + <xsd:enumeration value="thinDiagStripe"/> + <xsd:enumeration value="thinHorzCross"/> + <xsd:enumeration value="thinDiagCross"/> + <xsd:enumeration value="pct5"/> + <xsd:enumeration value="pct10"/> + <xsd:enumeration value="pct12"/> + <xsd:enumeration value="pct15"/> + <xsd:enumeration value="pct20"/> + <xsd:enumeration value="pct25"/> + <xsd:enumeration value="pct30"/> + <xsd:enumeration value="pct35"/> + <xsd:enumeration value="pct37"/> + <xsd:enumeration value="pct40"/> + <xsd:enumeration value="pct45"/> + <xsd:enumeration value="pct50"/> + <xsd:enumeration value="pct55"/> + <xsd:enumeration value="pct60"/> + <xsd:enumeration value="pct62"/> + <xsd:enumeration value="pct65"/> + <xsd:enumeration value="pct70"/> + <xsd:enumeration value="pct75"/> + <xsd:enumeration value="pct80"/> + <xsd:enumeration value="pct85"/> + <xsd:enumeration value="pct87"/> + <xsd:enumeration value="pct90"/> + <xsd:enumeration value="pct95"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Shd"> + <xsd:attribute name="val" type="ST_Shd" use="required"/> + <xsd:attribute name="color" type="ST_HexColor" use="optional"/> + <xsd:attribute name="themeColor" type="ST_ThemeColor" use="optional"/> + <xsd:attribute name="themeTint" type="ST_UcharHexNumber" use="optional"/> + <xsd:attribute name="themeShade" type="ST_UcharHexNumber" use="optional"/> + <xsd:attribute name="fill" type="ST_HexColor" use="optional"/> + <xsd:attribute name="themeFill" type="ST_ThemeColor" use="optional"/> + <xsd:attribute name="themeFillTint" type="ST_UcharHexNumber" use="optional"/> + <xsd:attribute name="themeFillShade" type="ST_UcharHexNumber" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_VerticalAlignRun"> + <xsd:attribute name="val" type="s:ST_VerticalAlignRun" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_FitText"> + <xsd:attribute name="val" type="s:ST_TwipsMeasure" use="required"/> + <xsd:attribute name="id" type="ST_DecimalNumber" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_Em"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="dot"/> + <xsd:enumeration value="comma"/> + <xsd:enumeration value="circle"/> + <xsd:enumeration value="underDot"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Em"> + <xsd:attribute name="val" type="ST_Em" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Language"> + <xsd:attribute name="val" type="s:ST_Lang" use="optional"/> + <xsd:attribute name="eastAsia" type="s:ST_Lang" use="optional"/> + <xsd:attribute name="bidi" type="s:ST_Lang" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_CombineBrackets"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="round"/> + <xsd:enumeration value="square"/> + <xsd:enumeration value="angle"/> + <xsd:enumeration value="curly"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_EastAsianLayout"> + <xsd:attribute name="id" type="ST_DecimalNumber" use="optional"/> + <xsd:attribute name="combine" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="combineBrackets" type="ST_CombineBrackets" use="optional"/> + <xsd:attribute name="vert" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="vertCompress" type="s:ST_OnOff" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_HeightRule"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="auto"/> + <xsd:enumeration value="exact"/> + <xsd:enumeration value="atLeast"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Wrap"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="auto"/> + <xsd:enumeration value="notBeside"/> + <xsd:enumeration value="around"/> + <xsd:enumeration value="tight"/> + <xsd:enumeration value="through"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_VAnchor"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="text"/> + <xsd:enumeration value="margin"/> + <xsd:enumeration value="page"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_HAnchor"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="text"/> + <xsd:enumeration value="margin"/> + <xsd:enumeration value="page"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_DropCap"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="drop"/> + <xsd:enumeration value="margin"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_FramePr"> + <xsd:attribute name="dropCap" type="ST_DropCap" use="optional"/> + <xsd:attribute name="lines" type="ST_DecimalNumber" use="optional"/> + <xsd:attribute name="w" type="s:ST_TwipsMeasure" use="optional"/> + <xsd:attribute name="h" type="s:ST_TwipsMeasure" use="optional"/> + <xsd:attribute name="vSpace" type="s:ST_TwipsMeasure" use="optional"/> + <xsd:attribute name="hSpace" type="s:ST_TwipsMeasure" use="optional"/> + <xsd:attribute name="wrap" type="ST_Wrap" use="optional"/> + <xsd:attribute name="hAnchor" type="ST_HAnchor" use="optional"/> + <xsd:attribute name="vAnchor" type="ST_VAnchor" use="optional"/> + <xsd:attribute name="x" type="ST_SignedTwipsMeasure" use="optional"/> + <xsd:attribute name="xAlign" type="s:ST_XAlign" use="optional"/> + <xsd:attribute name="y" type="ST_SignedTwipsMeasure" use="optional"/> + <xsd:attribute name="yAlign" type="s:ST_YAlign" use="optional"/> + <xsd:attribute name="hRule" type="ST_HeightRule" use="optional"/> + <xsd:attribute name="anchorLock" type="s:ST_OnOff" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_TabJc"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="clear"/> + <xsd:enumeration value="start"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="end"/> + <xsd:enumeration value="decimal"/> + <xsd:enumeration value="bar"/> + <xsd:enumeration value="num"/> + <xsd:enumeration value="left"/> + <xsd:enumeration value="right"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_TabTlc"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="dot"/> + <xsd:enumeration value="hyphen"/> + <xsd:enumeration value="underscore"/> + <xsd:enumeration value="heavy"/> + <xsd:enumeration value="middleDot"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TabStop"> + <xsd:attribute name="val" type="ST_TabJc" use="required"/> + <xsd:attribute name="leader" type="ST_TabTlc" use="optional"/> + <xsd:attribute name="pos" type="ST_SignedTwipsMeasure" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_LineSpacingRule"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="auto"/> + <xsd:enumeration value="exact"/> + <xsd:enumeration value="atLeast"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Spacing"> + <xsd:attribute name="before" type="s:ST_TwipsMeasure" use="optional" default="0"/> + <xsd:attribute name="beforeLines" type="ST_DecimalNumber" use="optional" default="0"/> + <xsd:attribute name="beforeAutospacing" type="s:ST_OnOff" use="optional" default="off"/> + <xsd:attribute name="after" type="s:ST_TwipsMeasure" use="optional" default="0"/> + <xsd:attribute name="afterLines" type="ST_DecimalNumber" use="optional" default="0"/> + <xsd:attribute name="afterAutospacing" type="s:ST_OnOff" use="optional" default="off"/> + <xsd:attribute name="line" type="ST_SignedTwipsMeasure" use="optional" default="0"/> + <xsd:attribute name="lineRule" type="ST_LineSpacingRule" use="optional" default="auto"/> + </xsd:complexType> + <xsd:complexType name="CT_Ind"> + <xsd:attribute name="start" type="ST_SignedTwipsMeasure" use="optional"/> + <xsd:attribute name="startChars" type="ST_DecimalNumber" use="optional"/> + <xsd:attribute name="end" type="ST_SignedTwipsMeasure" use="optional"/> + <xsd:attribute name="endChars" type="ST_DecimalNumber" use="optional"/> + <xsd:attribute name="left" type="ST_SignedTwipsMeasure" use="optional"/> + <xsd:attribute name="leftChars" type="ST_DecimalNumber" use="optional"/> + <xsd:attribute name="right" type="ST_SignedTwipsMeasure" use="optional"/> + <xsd:attribute name="rightChars" type="ST_DecimalNumber" use="optional"/> + <xsd:attribute name="hanging" type="s:ST_TwipsMeasure" use="optional"/> + <xsd:attribute name="hangingChars" type="ST_DecimalNumber" use="optional"/> + <xsd:attribute name="firstLine" type="s:ST_TwipsMeasure" use="optional"/> + <xsd:attribute name="firstLineChars" type="ST_DecimalNumber" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_Jc"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="start"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="end"/> + <xsd:enumeration value="both"/> + <xsd:enumeration value="mediumKashida"/> + <xsd:enumeration value="distribute"/> + <xsd:enumeration value="numTab"/> + <xsd:enumeration value="highKashida"/> + <xsd:enumeration value="lowKashida"/> + <xsd:enumeration value="thaiDistribute"/> + <xsd:enumeration value="left"/> + <xsd:enumeration value="right"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_JcTable"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="center"/> + <xsd:enumeration value="end"/> + <xsd:enumeration value="left"/> + <xsd:enumeration value="right"/> + <xsd:enumeration value="start"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Jc"> + <xsd:attribute name="val" type="ST_Jc" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_JcTable"> + <xsd:attribute name="val" type="ST_JcTable" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_View"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="print"/> + <xsd:enumeration value="outline"/> + <xsd:enumeration value="masterPages"/> + <xsd:enumeration value="normal"/> + <xsd:enumeration value="web"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_View"> + <xsd:attribute name="val" type="ST_View" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_Zoom"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="fullPage"/> + <xsd:enumeration value="bestFit"/> + <xsd:enumeration value="textFit"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Zoom"> + <xsd:attribute name="val" type="ST_Zoom" use="optional"/> + <xsd:attribute name="percent" type="ST_DecimalNumberOrPercent" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_WritingStyle"> + <xsd:attribute name="lang" type="s:ST_Lang" use="required"/> + <xsd:attribute name="vendorID" type="s:ST_String" use="required"/> + <xsd:attribute name="dllVersion" type="s:ST_String" use="required"/> + <xsd:attribute name="nlCheck" type="s:ST_OnOff" use="optional" default="off"/> + <xsd:attribute name="checkStyle" type="s:ST_OnOff" use="required"/> + <xsd:attribute name="appName" type="s:ST_String" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_Proof"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="clean"/> + <xsd:enumeration value="dirty"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Proof"> + <xsd:attribute name="spelling" type="ST_Proof" use="optional"/> + <xsd:attribute name="grammar" type="ST_Proof" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_DocType"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:complexType name="CT_DocType"> + <xsd:attribute name="val" type="ST_DocType" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_DocProtect"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="readOnly"/> + <xsd:enumeration value="comments"/> + <xsd:enumeration value="trackedChanges"/> + <xsd:enumeration value="forms"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:attributeGroup name="AG_Password"> + <xsd:attribute name="algorithmName" type="s:ST_String" use="optional"/> + <xsd:attribute name="hashValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="saltValue" type="xsd:base64Binary" use="optional"/> + <xsd:attribute name="spinCount" type="ST_DecimalNumber" use="optional"/> + </xsd:attributeGroup> + <xsd:attributeGroup name="AG_TransitionalPassword"> + <xsd:attribute name="cryptProviderType" type="s:ST_CryptProv"/> + <xsd:attribute name="cryptAlgorithmClass" type="s:ST_AlgClass"/> + <xsd:attribute name="cryptAlgorithmType" type="s:ST_AlgType"/> + <xsd:attribute name="cryptAlgorithmSid" type="ST_DecimalNumber"/> + <xsd:attribute name="cryptSpinCount" type="ST_DecimalNumber"/> + <xsd:attribute name="cryptProvider" type="s:ST_String"/> + <xsd:attribute name="algIdExt" type="ST_LongHexNumber"/> + <xsd:attribute name="algIdExtSource" type="s:ST_String"/> + <xsd:attribute name="cryptProviderTypeExt" type="ST_LongHexNumber"/> + <xsd:attribute name="cryptProviderTypeExtSource" type="s:ST_String"/> + <xsd:attribute name="hash" type="xsd:base64Binary"/> + <xsd:attribute name="salt" type="xsd:base64Binary"/> + </xsd:attributeGroup> + <xsd:complexType name="CT_DocProtect"> + <xsd:attribute name="edit" type="ST_DocProtect" use="optional"/> + <xsd:attribute name="formatting" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="enforcement" type="s:ST_OnOff"/> + <xsd:attributeGroup ref="AG_Password"/> + <xsd:attributeGroup ref="AG_TransitionalPassword"/> + </xsd:complexType> + <xsd:simpleType name="ST_MailMergeDocType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="catalog"/> + <xsd:enumeration value="envelopes"/> + <xsd:enumeration value="mailingLabels"/> + <xsd:enumeration value="formLetters"/> + <xsd:enumeration value="email"/> + <xsd:enumeration value="fax"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_MailMergeDocType"> + <xsd:attribute name="val" type="ST_MailMergeDocType" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_MailMergeDataType"> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + <xsd:complexType name="CT_MailMergeDataType"> + <xsd:attribute name="val" type="ST_MailMergeDataType" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_MailMergeDest"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="newDocument"/> + <xsd:enumeration value="printer"/> + <xsd:enumeration value="email"/> + <xsd:enumeration value="fax"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_MailMergeDest"> + <xsd:attribute name="val" type="ST_MailMergeDest" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_MailMergeOdsoFMDFieldType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="null"/> + <xsd:enumeration value="dbColumn"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_MailMergeOdsoFMDFieldType"> + <xsd:attribute name="val" type="ST_MailMergeOdsoFMDFieldType" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TrackChangesView"> + <xsd:attribute name="markup" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="comments" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="insDel" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="formatting" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="inkAnnotations" type="s:ST_OnOff" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Kinsoku"> + <xsd:attribute name="lang" type="s:ST_Lang" use="required"/> + <xsd:attribute name="val" type="s:ST_String" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_TextDirection"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="tb"/> + <xsd:enumeration value="rl"/> + <xsd:enumeration value="lr"/> + <xsd:enumeration value="tbV"/> + <xsd:enumeration value="rlV"/> + <xsd:enumeration value="lrV"/> + <xsd:enumeration value="btLr"/> + <xsd:enumeration value="lrTb"/> + <xsd:enumeration value="lrTbV"/> + <xsd:enumeration value="tbLrV"/> + <xsd:enumeration value="tbRl"/> + <xsd:enumeration value="tbRlV"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextDirection"> + <xsd:attribute name="val" type="ST_TextDirection" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_TextAlignment"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="top"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="baseline"/> + <xsd:enumeration value="bottom"/> + <xsd:enumeration value="auto"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextAlignment"> + <xsd:attribute name="val" type="ST_TextAlignment" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_DisplacedByCustomXml"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="next"/> + <xsd:enumeration value="prev"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_AnnotationVMerge"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="cont"/> + <xsd:enumeration value="rest"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Markup"> + <xsd:attribute name="id" type="ST_DecimalNumber" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TrackChange"> + <xsd:complexContent> + <xsd:extension base="CT_Markup"> + <xsd:attribute name="author" type="s:ST_String" use="required"/> + <xsd:attribute name="date" type="ST_DateTime" use="optional"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_CellMergeTrackChange"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:attribute name="vMerge" type="ST_AnnotationVMerge" use="optional"/> + <xsd:attribute name="vMergeOrig" type="ST_AnnotationVMerge" use="optional"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_TrackChangeRange"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:attribute name="displacedByCustomXml" type="ST_DisplacedByCustomXml" use="optional"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_MarkupRange"> + <xsd:complexContent> + <xsd:extension base="CT_Markup"> + <xsd:attribute name="displacedByCustomXml" type="ST_DisplacedByCustomXml" use="optional"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_BookmarkRange"> + <xsd:complexContent> + <xsd:extension base="CT_MarkupRange"> + <xsd:attribute name="colFirst" type="ST_DecimalNumber" use="optional"/> + <xsd:attribute name="colLast" type="ST_DecimalNumber" use="optional"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_Bookmark"> + <xsd:complexContent> + <xsd:extension base="CT_BookmarkRange"> + <xsd:attribute name="name" type="s:ST_String" use="required"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_MoveBookmark"> + <xsd:complexContent> + <xsd:extension base="CT_Bookmark"> + <xsd:attribute name="author" type="s:ST_String" use="required"/> + <xsd:attribute name="date" type="ST_DateTime" use="required"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_Comment"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:sequence> + <xsd:group ref="EG_BlockLevelElts" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="initials" type="s:ST_String" use="optional"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_TrackChangeNumbering"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:attribute name="original" type="s:ST_String" use="optional"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_TblPrExChange"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:sequence> + <xsd:element name="tblPrEx" type="CT_TblPrExBase" minOccurs="1"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_TcPrChange"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:sequence> + <xsd:element name="tcPr" type="CT_TcPrInner" minOccurs="1"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_TrPrChange"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:sequence> + <xsd:element name="trPr" type="CT_TrPrBase" minOccurs="1"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_TblGridChange"> + <xsd:complexContent> + <xsd:extension base="CT_Markup"> + <xsd:sequence> + <xsd:element name="tblGrid" type="CT_TblGridBase"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_TblPrChange"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:sequence> + <xsd:element name="tblPr" type="CT_TblPrBase"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_SectPrChange"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:sequence> + <xsd:element name="sectPr" type="CT_SectPrBase" minOccurs="0"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_PPrChange"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:sequence> + <xsd:element name="pPr" type="CT_PPrBase" minOccurs="1"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_RPrChange"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:sequence> + <xsd:element name="rPr" type="CT_RPrOriginal" minOccurs="1"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_ParaRPrChange"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:sequence> + <xsd:element name="rPr" type="CT_ParaRPrOriginal" minOccurs="1"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_RunTrackChange"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:group ref="EG_ContentRunContent"/> + <xsd:group ref="m:EG_OMathMathElements"/> + </xsd:choice> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:group name="EG_PContentMath"> + <xsd:choice> + <xsd:group ref="EG_PContentBase" minOccurs="0" maxOccurs="unbounded"/> + <xsd:group ref="EG_ContentRunContentBase" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:group> + <xsd:group name="EG_PContentBase"> + <xsd:choice> + <xsd:element name="customXml" type="CT_CustomXmlRun"/> + <xsd:element name="fldSimple" type="CT_SimpleField" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="hyperlink" type="CT_Hyperlink"/> + </xsd:choice> + </xsd:group> + <xsd:group name="EG_ContentRunContentBase"> + <xsd:choice> + <xsd:element name="smartTag" type="CT_SmartTagRun"/> + <xsd:element name="sdt" type="CT_SdtRun"/> + <xsd:group ref="EG_RunLevelElts" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:group> + <xsd:group name="EG_CellMarkupElements"> + <xsd:choice> + <xsd:element name="cellIns" type="CT_TrackChange" minOccurs="0"/> + <xsd:element name="cellDel" type="CT_TrackChange" minOccurs="0"/> + <xsd:element name="cellMerge" type="CT_CellMergeTrackChange" minOccurs="0"/> + </xsd:choice> + </xsd:group> + <xsd:group name="EG_RangeMarkupElements"> + <xsd:choice> + <xsd:element name="bookmarkStart" type="CT_Bookmark"/> + <xsd:element name="bookmarkEnd" type="CT_MarkupRange"/> + <xsd:element name="moveFromRangeStart" type="CT_MoveBookmark"/> + <xsd:element name="moveFromRangeEnd" type="CT_MarkupRange"/> + <xsd:element name="moveToRangeStart" type="CT_MoveBookmark"/> + <xsd:element name="moveToRangeEnd" type="CT_MarkupRange"/> + <xsd:element name="commentRangeStart" type="CT_MarkupRange"/> + <xsd:element name="commentRangeEnd" type="CT_MarkupRange"/> + <xsd:element name="customXmlInsRangeStart" type="CT_TrackChange"/> + <xsd:element name="customXmlInsRangeEnd" type="CT_Markup"/> + <xsd:element name="customXmlDelRangeStart" type="CT_TrackChange"/> + <xsd:element name="customXmlDelRangeEnd" type="CT_Markup"/> + <xsd:element name="customXmlMoveFromRangeStart" type="CT_TrackChange"/> + <xsd:element name="customXmlMoveFromRangeEnd" type="CT_Markup"/> + <xsd:element name="customXmlMoveToRangeStart" type="CT_TrackChange"/> + <xsd:element name="customXmlMoveToRangeEnd" type="CT_Markup"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_NumPr"> + <xsd:sequence> + <xsd:element name="ilvl" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="numId" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="numberingChange" type="CT_TrackChangeNumbering" minOccurs="0"/> + <xsd:element name="ins" type="CT_TrackChange" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PBdr"> + <xsd:sequence> + <xsd:element name="top" type="CT_Border" minOccurs="0"/> + <xsd:element name="left" type="CT_Border" minOccurs="0"/> + <xsd:element name="bottom" type="CT_Border" minOccurs="0"/> + <xsd:element name="right" type="CT_Border" minOccurs="0"/> + <xsd:element name="between" type="CT_Border" minOccurs="0"/> + <xsd:element name="bar" type="CT_Border" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Tabs"> + <xsd:sequence> + <xsd:element name="tab" type="CT_TabStop" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_TextboxTightWrap"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="allLines"/> + <xsd:enumeration value="firstAndLastLine"/> + <xsd:enumeration value="firstLineOnly"/> + <xsd:enumeration value="lastLineOnly"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TextboxTightWrap"> + <xsd:attribute name="val" type="ST_TextboxTightWrap" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_PPrBase"> + <xsd:sequence> + <xsd:element name="pStyle" type="CT_String" minOccurs="0"/> + <xsd:element name="keepNext" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="keepLines" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="pageBreakBefore" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="framePr" type="CT_FramePr" minOccurs="0"/> + <xsd:element name="widowControl" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="numPr" type="CT_NumPr" minOccurs="0"/> + <xsd:element name="suppressLineNumbers" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="pBdr" type="CT_PBdr" minOccurs="0"/> + <xsd:element name="shd" type="CT_Shd" minOccurs="0"/> + <xsd:element name="tabs" type="CT_Tabs" minOccurs="0"/> + <xsd:element name="suppressAutoHyphens" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="kinsoku" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="wordWrap" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="overflowPunct" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="topLinePunct" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="autoSpaceDE" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="autoSpaceDN" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="bidi" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="adjustRightInd" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="snapToGrid" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="spacing" type="CT_Spacing" minOccurs="0"/> + <xsd:element name="ind" type="CT_Ind" minOccurs="0"/> + <xsd:element name="contextualSpacing" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="mirrorIndents" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="suppressOverlap" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="jc" type="CT_Jc" minOccurs="0"/> + <xsd:element name="textDirection" type="CT_TextDirection" minOccurs="0"/> + <xsd:element name="textAlignment" type="CT_TextAlignment" minOccurs="0"/> + <xsd:element name="textboxTightWrap" type="CT_TextboxTightWrap" minOccurs="0"/> + <xsd:element name="outlineLvl" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="divId" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="cnfStyle" type="CT_Cnf" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PPr"> + <xsd:complexContent> + <xsd:extension base="CT_PPrBase"> + <xsd:sequence> + <xsd:element name="rPr" type="CT_ParaRPr" minOccurs="0"/> + <xsd:element name="sectPr" type="CT_SectPr" minOccurs="0"/> + <xsd:element name="pPrChange" type="CT_PPrChange" minOccurs="0"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_PPrGeneral"> + <xsd:complexContent> + <xsd:extension base="CT_PPrBase"> + <xsd:sequence> + <xsd:element name="pPrChange" type="CT_PPrChange" minOccurs="0"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_Control"> + <xsd:attribute name="name" type="s:ST_String" use="optional"/> + <xsd:attribute name="shapeid" type="s:ST_String" use="optional"/> + <xsd:attribute ref="r:id" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Background"> + <xsd:sequence> + <xsd:sequence maxOccurs="unbounded"> + <xsd:any processContents="lax" namespace="urn:schemas-microsoft-com:vml" minOccurs="0" + maxOccurs="unbounded"/> + <xsd:any processContents="lax" namespace="urn:schemas-microsoft-com:office:office" + minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:element name="drawing" type="CT_Drawing" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="color" type="ST_HexColor" use="optional" default="auto"/> + <xsd:attribute name="themeColor" type="ST_ThemeColor" use="optional"/> + <xsd:attribute name="themeTint" type="ST_UcharHexNumber" use="optional"/> + <xsd:attribute name="themeShade" type="ST_UcharHexNumber" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Rel"> + <xsd:attribute ref="r:id" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Object"> + <xsd:sequence> + <xsd:sequence maxOccurs="unbounded"> + <xsd:any processContents="lax" namespace="urn:schemas-microsoft-com:vml" minOccurs="0" + maxOccurs="unbounded"/> + <xsd:any processContents="lax" namespace="urn:schemas-microsoft-com:office:office" + minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:element name="drawing" type="CT_Drawing" minOccurs="0"/> + <xsd:choice minOccurs="0"> + <xsd:element name="control" type="CT_Control"/> + <xsd:element name="objectLink" type="CT_ObjectLink"/> + <xsd:element name="objectEmbed" type="CT_ObjectEmbed"/> + <xsd:element name="movie" type="CT_Rel"/> + </xsd:choice> + </xsd:sequence> + <xsd:attribute name="dxaOrig" type="s:ST_TwipsMeasure" use="optional"/> + <xsd:attribute name="dyaOrig" type="s:ST_TwipsMeasure" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Picture"> + <xsd:sequence> + <xsd:sequence maxOccurs="unbounded"> + <xsd:any processContents="lax" namespace="urn:schemas-microsoft-com:vml" minOccurs="0" + maxOccurs="unbounded"/> + <xsd:any processContents="lax" namespace="urn:schemas-microsoft-com:office:office" + minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:element name="movie" type="CT_Rel" minOccurs="0"/> + <xsd:element name="control" type="CT_Control" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ObjectEmbed"> + <xsd:attribute name="drawAspect" type="ST_ObjectDrawAspect" use="optional"/> + <xsd:attribute ref="r:id" use="required"/> + <xsd:attribute name="progId" type="s:ST_String" use="optional"/> + <xsd:attribute name="shapeId" type="s:ST_String" use="optional"/> + <xsd:attribute name="fieldCodes" type="s:ST_String" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_ObjectDrawAspect"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="content"/> + <xsd:enumeration value="icon"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_ObjectLink"> + <xsd:complexContent> + <xsd:extension base="CT_ObjectEmbed"> + <xsd:attribute name="updateMode" type="ST_ObjectUpdateMode" use="required"/> + <xsd:attribute name="lockedField" type="s:ST_OnOff" use="optional"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:simpleType name="ST_ObjectUpdateMode"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="always"/> + <xsd:enumeration value="onCall"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Drawing"> + <xsd:choice minOccurs="1" maxOccurs="unbounded"> + <xsd:element ref="wp:anchor" minOccurs="0"/> + <xsd:element ref="wp:inline" minOccurs="0"/> + </xsd:choice> + </xsd:complexType> + <xsd:complexType name="CT_SimpleField"> + <xsd:sequence> + <xsd:element name="fldData" type="CT_Text" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="instr" type="s:ST_String" use="required"/> + <xsd:attribute name="fldLock" type="s:ST_OnOff"/> + <xsd:attribute name="dirty" type="s:ST_OnOff"/> + </xsd:complexType> + <xsd:simpleType name="ST_FldCharType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="begin"/> + <xsd:enumeration value="separate"/> + <xsd:enumeration value="end"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_InfoTextType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="text"/> + <xsd:enumeration value="autoText"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FFHelpTextVal"> + <xsd:restriction base="xsd:string"> + <xsd:maxLength value="256"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FFStatusTextVal"> + <xsd:restriction base="xsd:string"> + <xsd:maxLength value="140"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FFName"> + <xsd:restriction base="xsd:string"> + <xsd:maxLength value="65"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FFTextType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="regular"/> + <xsd:enumeration value="number"/> + <xsd:enumeration value="date"/> + <xsd:enumeration value="currentTime"/> + <xsd:enumeration value="currentDate"/> + <xsd:enumeration value="calculated"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_FFTextType"> + <xsd:attribute name="val" type="ST_FFTextType" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_FFName"> + <xsd:attribute name="val" type="ST_FFName"/> + </xsd:complexType> + <xsd:complexType name="CT_FldChar"> + <xsd:choice> + <xsd:element name="fldData" type="CT_Text" minOccurs="0" maxOccurs="1"/> + <xsd:element name="ffData" type="CT_FFData" minOccurs="0" maxOccurs="1"/> + <xsd:element name="numberingChange" type="CT_TrackChangeNumbering" minOccurs="0"/> + </xsd:choice> + <xsd:attribute name="fldCharType" type="ST_FldCharType" use="required"/> + <xsd:attribute name="fldLock" type="s:ST_OnOff"/> + <xsd:attribute name="dirty" type="s:ST_OnOff"/> + </xsd:complexType> + <xsd:complexType name="CT_Hyperlink"> + <xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded"/> + <xsd:attribute name="tgtFrame" type="s:ST_String" use="optional"/> + <xsd:attribute name="tooltip" type="s:ST_String" use="optional"/> + <xsd:attribute name="docLocation" type="s:ST_String" use="optional"/> + <xsd:attribute name="history" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="anchor" type="s:ST_String" use="optional"/> + <xsd:attribute ref="r:id"/> + </xsd:complexType> + <xsd:complexType name="CT_FFData"> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="name" type="CT_FFName"/> + <xsd:element name="label" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="tabIndex" type="CT_UnsignedDecimalNumber" minOccurs="0"/> + <xsd:element name="enabled" type="CT_OnOff"/> + <xsd:element name="calcOnExit" type="CT_OnOff"/> + <xsd:element name="entryMacro" type="CT_MacroName" minOccurs="0" maxOccurs="1"/> + <xsd:element name="exitMacro" type="CT_MacroName" minOccurs="0" maxOccurs="1"/> + <xsd:element name="helpText" type="CT_FFHelpText" minOccurs="0" maxOccurs="1"/> + <xsd:element name="statusText" type="CT_FFStatusText" minOccurs="0" maxOccurs="1"/> + <xsd:choice> + <xsd:element name="checkBox" type="CT_FFCheckBox"/> + <xsd:element name="ddList" type="CT_FFDDList"/> + <xsd:element name="textInput" type="CT_FFTextInput"/> + </xsd:choice> + </xsd:choice> + </xsd:complexType> + <xsd:complexType name="CT_FFHelpText"> + <xsd:attribute name="type" type="ST_InfoTextType"/> + <xsd:attribute name="val" type="ST_FFHelpTextVal"/> + </xsd:complexType> + <xsd:complexType name="CT_FFStatusText"> + <xsd:attribute name="type" type="ST_InfoTextType"/> + <xsd:attribute name="val" type="ST_FFStatusTextVal"/> + </xsd:complexType> + <xsd:complexType name="CT_FFCheckBox"> + <xsd:sequence> + <xsd:choice> + <xsd:element name="size" type="CT_HpsMeasure"/> + <xsd:element name="sizeAuto" type="CT_OnOff"/> + </xsd:choice> + <xsd:element name="default" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="checked" type="CT_OnOff" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_FFDDList"> + <xsd:sequence> + <xsd:element name="result" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="default" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="listEntry" type="CT_String" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_FFTextInput"> + <xsd:sequence> + <xsd:element name="type" type="CT_FFTextType" minOccurs="0"/> + <xsd:element name="default" type="CT_String" minOccurs="0"/> + <xsd:element name="maxLength" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="format" type="CT_String" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_SectionMark"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="nextPage"/> + <xsd:enumeration value="nextColumn"/> + <xsd:enumeration value="continuous"/> + <xsd:enumeration value="evenPage"/> + <xsd:enumeration value="oddPage"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SectType"> + <xsd:attribute name="val" type="ST_SectionMark"/> + </xsd:complexType> + <xsd:complexType name="CT_PaperSource"> + <xsd:attribute name="first" type="ST_DecimalNumber"/> + <xsd:attribute name="other" type="ST_DecimalNumber"/> + </xsd:complexType> + <xsd:simpleType name="ST_NumberFormat"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="decimal"/> + <xsd:enumeration value="upperRoman"/> + <xsd:enumeration value="lowerRoman"/> + <xsd:enumeration value="upperLetter"/> + <xsd:enumeration value="lowerLetter"/> + <xsd:enumeration value="ordinal"/> + <xsd:enumeration value="cardinalText"/> + <xsd:enumeration value="ordinalText"/> + <xsd:enumeration value="hex"/> + <xsd:enumeration value="chicago"/> + <xsd:enumeration value="ideographDigital"/> + <xsd:enumeration value="japaneseCounting"/> + <xsd:enumeration value="aiueo"/> + <xsd:enumeration value="iroha"/> + <xsd:enumeration value="decimalFullWidth"/> + <xsd:enumeration value="decimalHalfWidth"/> + <xsd:enumeration value="japaneseLegal"/> + <xsd:enumeration value="japaneseDigitalTenThousand"/> + <xsd:enumeration value="decimalEnclosedCircle"/> + <xsd:enumeration value="decimalFullWidth2"/> + <xsd:enumeration value="aiueoFullWidth"/> + <xsd:enumeration value="irohaFullWidth"/> + <xsd:enumeration value="decimalZero"/> + <xsd:enumeration value="bullet"/> + <xsd:enumeration value="ganada"/> + <xsd:enumeration value="chosung"/> + <xsd:enumeration value="decimalEnclosedFullstop"/> + <xsd:enumeration value="decimalEnclosedParen"/> + <xsd:enumeration value="decimalEnclosedCircleChinese"/> + <xsd:enumeration value="ideographEnclosedCircle"/> + <xsd:enumeration value="ideographTraditional"/> + <xsd:enumeration value="ideographZodiac"/> + <xsd:enumeration value="ideographZodiacTraditional"/> + <xsd:enumeration value="taiwaneseCounting"/> + <xsd:enumeration value="ideographLegalTraditional"/> + <xsd:enumeration value="taiwaneseCountingThousand"/> + <xsd:enumeration value="taiwaneseDigital"/> + <xsd:enumeration value="chineseCounting"/> + <xsd:enumeration value="chineseLegalSimplified"/> + <xsd:enumeration value="chineseCountingThousand"/> + <xsd:enumeration value="koreanDigital"/> + <xsd:enumeration value="koreanCounting"/> + <xsd:enumeration value="koreanLegal"/> + <xsd:enumeration value="koreanDigital2"/> + <xsd:enumeration value="vietnameseCounting"/> + <xsd:enumeration value="russianLower"/> + <xsd:enumeration value="russianUpper"/> + <xsd:enumeration value="none"/> + <xsd:enumeration value="numberInDash"/> + <xsd:enumeration value="hebrew1"/> + <xsd:enumeration value="hebrew2"/> + <xsd:enumeration value="arabicAlpha"/> + <xsd:enumeration value="arabicAbjad"/> + <xsd:enumeration value="hindiVowels"/> + <xsd:enumeration value="hindiConsonants"/> + <xsd:enumeration value="hindiNumbers"/> + <xsd:enumeration value="hindiCounting"/> + <xsd:enumeration value="thaiLetters"/> + <xsd:enumeration value="thaiNumbers"/> + <xsd:enumeration value="thaiCounting"/> + <xsd:enumeration value="bahtText"/> + <xsd:enumeration value="dollarText"/> + <xsd:enumeration value="custom"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PageOrientation"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="portrait"/> + <xsd:enumeration value="landscape"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PageSz"> + <xsd:attribute name="w" type="s:ST_TwipsMeasure"/> + <xsd:attribute name="h" type="s:ST_TwipsMeasure"/> + <xsd:attribute name="orient" type="ST_PageOrientation" use="optional"/> + <xsd:attribute name="code" type="ST_DecimalNumber" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_PageMar"> + <xsd:attribute name="top" type="ST_SignedTwipsMeasure" use="required"/> + <xsd:attribute name="right" type="s:ST_TwipsMeasure" use="required"/> + <xsd:attribute name="bottom" type="ST_SignedTwipsMeasure" use="required"/> + <xsd:attribute name="left" type="s:ST_TwipsMeasure" use="required"/> + <xsd:attribute name="header" type="s:ST_TwipsMeasure" use="required"/> + <xsd:attribute name="footer" type="s:ST_TwipsMeasure" use="required"/> + <xsd:attribute name="gutter" type="s:ST_TwipsMeasure" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_PageBorderZOrder"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="front"/> + <xsd:enumeration value="back"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PageBorderDisplay"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="allPages"/> + <xsd:enumeration value="firstPage"/> + <xsd:enumeration value="notFirstPage"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PageBorderOffset"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="page"/> + <xsd:enumeration value="text"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PageBorders"> + <xsd:sequence> + <xsd:element name="top" type="CT_TopPageBorder" minOccurs="0"/> + <xsd:element name="left" type="CT_PageBorder" minOccurs="0"/> + <xsd:element name="bottom" type="CT_BottomPageBorder" minOccurs="0"/> + <xsd:element name="right" type="CT_PageBorder" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="zOrder" type="ST_PageBorderZOrder" use="optional" default="front"/> + <xsd:attribute name="display" type="ST_PageBorderDisplay" use="optional"/> + <xsd:attribute name="offsetFrom" type="ST_PageBorderOffset" use="optional" default="text"/> + </xsd:complexType> + <xsd:complexType name="CT_PageBorder"> + <xsd:complexContent> + <xsd:extension base="CT_Border"> + <xsd:attribute ref="r:id" use="optional"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_BottomPageBorder"> + <xsd:complexContent> + <xsd:extension base="CT_PageBorder"> + <xsd:attribute ref="r:bottomLeft" use="optional"/> + <xsd:attribute ref="r:bottomRight" use="optional"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_TopPageBorder"> + <xsd:complexContent> + <xsd:extension base="CT_PageBorder"> + <xsd:attribute ref="r:topLeft" use="optional"/> + <xsd:attribute ref="r:topRight" use="optional"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:simpleType name="ST_ChapterSep"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="hyphen"/> + <xsd:enumeration value="period"/> + <xsd:enumeration value="colon"/> + <xsd:enumeration value="emDash"/> + <xsd:enumeration value="enDash"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_LineNumberRestart"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="newPage"/> + <xsd:enumeration value="newSection"/> + <xsd:enumeration value="continuous"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_LineNumber"> + <xsd:attribute name="countBy" type="ST_DecimalNumber" use="optional"/> + <xsd:attribute name="start" type="ST_DecimalNumber" use="optional" default="1"/> + <xsd:attribute name="distance" type="s:ST_TwipsMeasure" use="optional"/> + <xsd:attribute name="restart" type="ST_LineNumberRestart" use="optional" default="newPage"/> + </xsd:complexType> + <xsd:complexType name="CT_PageNumber"> + <xsd:attribute name="fmt" type="ST_NumberFormat" use="optional" default="decimal"/> + <xsd:attribute name="start" type="ST_DecimalNumber" use="optional"/> + <xsd:attribute name="chapStyle" type="ST_DecimalNumber" use="optional"/> + <xsd:attribute name="chapSep" type="ST_ChapterSep" use="optional" default="hyphen"/> + </xsd:complexType> + <xsd:complexType name="CT_Column"> + <xsd:attribute name="w" type="s:ST_TwipsMeasure" use="optional"/> + <xsd:attribute name="space" type="s:ST_TwipsMeasure" use="optional" default="0"/> + </xsd:complexType> + <xsd:complexType name="CT_Columns"> + <xsd:sequence minOccurs="0"> + <xsd:element name="col" type="CT_Column" maxOccurs="45"/> + </xsd:sequence> + <xsd:attribute name="equalWidth" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="space" type="s:ST_TwipsMeasure" use="optional" default="720"/> + <xsd:attribute name="num" type="ST_DecimalNumber" use="optional" default="1"/> + <xsd:attribute name="sep" type="s:ST_OnOff" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_VerticalJc"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="top"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="both"/> + <xsd:enumeration value="bottom"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_VerticalJc"> + <xsd:attribute name="val" type="ST_VerticalJc" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_DocGrid"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="default"/> + <xsd:enumeration value="lines"/> + <xsd:enumeration value="linesAndChars"/> + <xsd:enumeration value="snapToChars"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_DocGrid"> + <xsd:attribute name="type" type="ST_DocGrid"/> + <xsd:attribute name="linePitch" type="ST_DecimalNumber"/> + <xsd:attribute name="charSpace" type="ST_DecimalNumber"/> + </xsd:complexType> + <xsd:simpleType name="ST_HdrFtr"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="even"/> + <xsd:enumeration value="default"/> + <xsd:enumeration value="first"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_FtnEdn"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="normal"/> + <xsd:enumeration value="separator"/> + <xsd:enumeration value="continuationSeparator"/> + <xsd:enumeration value="continuationNotice"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_HdrFtrRef"> + <xsd:complexContent> + <xsd:extension base="CT_Rel"> + <xsd:attribute name="type" type="ST_HdrFtr" use="required"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:group name="EG_HdrFtrReferences"> + <xsd:choice> + <xsd:element name="headerReference" type="CT_HdrFtrRef" minOccurs="0"/> + <xsd:element name="footerReference" type="CT_HdrFtrRef" minOccurs="0"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_HdrFtr"> + <xsd:group ref="EG_BlockLevelElts" minOccurs="1" maxOccurs="unbounded"/> + </xsd:complexType> + <xsd:group name="EG_SectPrContents"> + <xsd:sequence> + <xsd:element name="footnotePr" type="CT_FtnProps" minOccurs="0"/> + <xsd:element name="endnotePr" type="CT_EdnProps" minOccurs="0"/> + <xsd:element name="type" type="CT_SectType" minOccurs="0"/> + <xsd:element name="pgSz" type="CT_PageSz" minOccurs="0"/> + <xsd:element name="pgMar" type="CT_PageMar" minOccurs="0"/> + <xsd:element name="paperSrc" type="CT_PaperSource" minOccurs="0"/> + <xsd:element name="pgBorders" type="CT_PageBorders" minOccurs="0"/> + <xsd:element name="lnNumType" type="CT_LineNumber" minOccurs="0"/> + <xsd:element name="pgNumType" type="CT_PageNumber" minOccurs="0"/> + <xsd:element name="cols" type="CT_Columns" minOccurs="0"/> + <xsd:element name="formProt" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="vAlign" type="CT_VerticalJc" minOccurs="0"/> + <xsd:element name="noEndnote" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="titlePg" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="textDirection" type="CT_TextDirection" minOccurs="0"/> + <xsd:element name="bidi" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="rtlGutter" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="docGrid" type="CT_DocGrid" minOccurs="0"/> + <xsd:element name="printerSettings" type="CT_Rel" minOccurs="0"/> + </xsd:sequence> + </xsd:group> + <xsd:attributeGroup name="AG_SectPrAttributes"> + <xsd:attribute name="rsidRPr" type="ST_LongHexNumber"/> + <xsd:attribute name="rsidDel" type="ST_LongHexNumber"/> + <xsd:attribute name="rsidR" type="ST_LongHexNumber"/> + <xsd:attribute name="rsidSect" type="ST_LongHexNumber"/> + </xsd:attributeGroup> + <xsd:complexType name="CT_SectPrBase"> + <xsd:sequence> + <xsd:group ref="EG_SectPrContents" minOccurs="0"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_SectPrAttributes"/> + </xsd:complexType> + <xsd:complexType name="CT_SectPr"> + <xsd:sequence> + <xsd:group ref="EG_HdrFtrReferences" minOccurs="0" maxOccurs="6"/> + <xsd:group ref="EG_SectPrContents" minOccurs="0"/> + <xsd:element name="sectPrChange" type="CT_SectPrChange" minOccurs="0"/> + </xsd:sequence> + <xsd:attributeGroup ref="AG_SectPrAttributes"/> + </xsd:complexType> + <xsd:simpleType name="ST_BrType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="page"/> + <xsd:enumeration value="column"/> + <xsd:enumeration value="textWrapping"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_BrClear"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="left"/> + <xsd:enumeration value="right"/> + <xsd:enumeration value="all"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Br"> + <xsd:attribute name="type" type="ST_BrType" use="optional"/> + <xsd:attribute name="clear" type="ST_BrClear" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_PTabAlignment"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="left"/> + <xsd:enumeration value="center"/> + <xsd:enumeration value="right"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PTabRelativeTo"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="margin"/> + <xsd:enumeration value="indent"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PTabLeader"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="dot"/> + <xsd:enumeration value="hyphen"/> + <xsd:enumeration value="underscore"/> + <xsd:enumeration value="middleDot"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_PTab"> + <xsd:attribute name="alignment" type="ST_PTabAlignment" use="required"/> + <xsd:attribute name="relativeTo" type="ST_PTabRelativeTo" use="required"/> + <xsd:attribute name="leader" type="ST_PTabLeader" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Sym"> + <xsd:attribute name="font" type="s:ST_String"/> + <xsd:attribute name="char" type="ST_ShortHexNumber"/> + </xsd:complexType> + <xsd:simpleType name="ST_ProofErr"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="spellStart"/> + <xsd:enumeration value="spellEnd"/> + <xsd:enumeration value="gramStart"/> + <xsd:enumeration value="gramEnd"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_ProofErr"> + <xsd:attribute name="type" type="ST_ProofErr" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_EdGrp"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="everyone"/> + <xsd:enumeration value="administrators"/> + <xsd:enumeration value="contributors"/> + <xsd:enumeration value="editors"/> + <xsd:enumeration value="owners"/> + <xsd:enumeration value="current"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Perm"> + <xsd:attribute name="id" type="s:ST_String" use="required"/> + <xsd:attribute name="displacedByCustomXml" type="ST_DisplacedByCustomXml" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_PermStart"> + <xsd:complexContent> + <xsd:extension base="CT_Perm"> + <xsd:attribute name="edGrp" type="ST_EdGrp" use="optional"/> + <xsd:attribute name="ed" type="s:ST_String" use="optional"/> + <xsd:attribute name="colFirst" type="ST_DecimalNumber" use="optional"/> + <xsd:attribute name="colLast" type="ST_DecimalNumber" use="optional"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_Text"> + <xsd:simpleContent> + <xsd:extension base="s:ST_String"> + <xsd:attribute ref="xml:space" use="optional"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + <xsd:group name="EG_RunInnerContent"> + <xsd:choice> + <xsd:element name="br" type="CT_Br"/> + <xsd:element name="t" type="CT_Text"/> + <xsd:element name="contentPart" type="CT_Rel"/> + <xsd:element name="delText" type="CT_Text"/> + <xsd:element name="instrText" type="CT_Text"/> + <xsd:element name="delInstrText" type="CT_Text"/> + <xsd:element name="noBreakHyphen" type="CT_Empty"/> + <xsd:element name="softHyphen" type="CT_Empty" minOccurs="0"/> + <xsd:element name="dayShort" type="CT_Empty" minOccurs="0"/> + <xsd:element name="monthShort" type="CT_Empty" minOccurs="0"/> + <xsd:element name="yearShort" type="CT_Empty" minOccurs="0"/> + <xsd:element name="dayLong" type="CT_Empty" minOccurs="0"/> + <xsd:element name="monthLong" type="CT_Empty" minOccurs="0"/> + <xsd:element name="yearLong" type="CT_Empty" minOccurs="0"/> + <xsd:element name="annotationRef" type="CT_Empty" minOccurs="0"/> + <xsd:element name="footnoteRef" type="CT_Empty" minOccurs="0"/> + <xsd:element name="endnoteRef" type="CT_Empty" minOccurs="0"/> + <xsd:element name="separator" type="CT_Empty" minOccurs="0"/> + <xsd:element name="continuationSeparator" type="CT_Empty" minOccurs="0"/> + <xsd:element name="sym" type="CT_Sym" minOccurs="0"/> + <xsd:element name="pgNum" type="CT_Empty" minOccurs="0"/> + <xsd:element name="cr" type="CT_Empty" minOccurs="0"/> + <xsd:element name="tab" type="CT_Empty" minOccurs="0"/> + <xsd:element name="object" type="CT_Object"/> + <xsd:element name="pict" type="CT_Picture"/> + <xsd:element name="fldChar" type="CT_FldChar"/> + <xsd:element name="ruby" type="CT_Ruby"/> + <xsd:element name="footnoteReference" type="CT_FtnEdnRef"/> + <xsd:element name="endnoteReference" type="CT_FtnEdnRef"/> + <xsd:element name="commentReference" type="CT_Markup"/> + <xsd:element name="drawing" type="CT_Drawing"/> + <xsd:element name="ptab" type="CT_PTab" minOccurs="0"/> + <xsd:element name="lastRenderedPageBreak" type="CT_Empty" minOccurs="0" maxOccurs="1"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_R"> + <xsd:sequence> + <xsd:group ref="EG_RPr" minOccurs="0"/> + <xsd:group ref="EG_RunInnerContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="rsidRPr" type="ST_LongHexNumber"/> + <xsd:attribute name="rsidDel" type="ST_LongHexNumber"/> + <xsd:attribute name="rsidR" type="ST_LongHexNumber"/> + </xsd:complexType> + <xsd:simpleType name="ST_Hint"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="default"/> + <xsd:enumeration value="eastAsia"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_Theme"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="majorEastAsia"/> + <xsd:enumeration value="majorBidi"/> + <xsd:enumeration value="majorAscii"/> + <xsd:enumeration value="majorHAnsi"/> + <xsd:enumeration value="minorEastAsia"/> + <xsd:enumeration value="minorBidi"/> + <xsd:enumeration value="minorAscii"/> + <xsd:enumeration value="minorHAnsi"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Fonts"> + <xsd:attribute name="hint" type="ST_Hint"/> + <xsd:attribute name="ascii" type="s:ST_String"/> + <xsd:attribute name="hAnsi" type="s:ST_String"/> + <xsd:attribute name="eastAsia" type="s:ST_String"/> + <xsd:attribute name="cs" type="s:ST_String"/> + <xsd:attribute name="asciiTheme" type="ST_Theme"/> + <xsd:attribute name="hAnsiTheme" type="ST_Theme"/> + <xsd:attribute name="eastAsiaTheme" type="ST_Theme"/> + <xsd:attribute name="cstheme" type="ST_Theme"/> + </xsd:complexType> + <xsd:group name="EG_RPrBase"> + <xsd:choice> + <xsd:element name="rStyle" type="CT_String"/> + <xsd:element name="rFonts" type="CT_Fonts"/> + <xsd:element name="b" type="CT_OnOff"/> + <xsd:element name="bCs" type="CT_OnOff"/> + <xsd:element name="i" type="CT_OnOff"/> + <xsd:element name="iCs" type="CT_OnOff"/> + <xsd:element name="caps" type="CT_OnOff"/> + <xsd:element name="smallCaps" type="CT_OnOff"/> + <xsd:element name="strike" type="CT_OnOff"/> + <xsd:element name="dstrike" type="CT_OnOff"/> + <xsd:element name="outline" type="CT_OnOff"/> + <xsd:element name="shadow" type="CT_OnOff"/> + <xsd:element name="emboss" type="CT_OnOff"/> + <xsd:element name="imprint" type="CT_OnOff"/> + <xsd:element name="noProof" type="CT_OnOff"/> + <xsd:element name="snapToGrid" type="CT_OnOff"/> + <xsd:element name="vanish" type="CT_OnOff"/> + <xsd:element name="webHidden" type="CT_OnOff"/> + <xsd:element name="color" type="CT_Color"/> + <xsd:element name="spacing" type="CT_SignedTwipsMeasure"/> + <xsd:element name="w" type="CT_TextScale"/> + <xsd:element name="kern" type="CT_HpsMeasure"/> + <xsd:element name="position" type="CT_SignedHpsMeasure"/> + <xsd:element name="sz" type="CT_HpsMeasure"/> + <xsd:element name="szCs" type="CT_HpsMeasure"/> + <xsd:element name="highlight" type="CT_Highlight"/> + <xsd:element name="u" type="CT_Underline"/> + <xsd:element name="effect" type="CT_TextEffect"/> + <xsd:element name="bdr" type="CT_Border"/> + <xsd:element name="shd" type="CT_Shd"/> + <xsd:element name="fitText" type="CT_FitText"/> + <xsd:element name="vertAlign" type="CT_VerticalAlignRun"/> + <xsd:element name="rtl" type="CT_OnOff"/> + <xsd:element name="cs" type="CT_OnOff"/> + <xsd:element name="em" type="CT_Em"/> + <xsd:element name="lang" type="CT_Language"/> + <xsd:element name="eastAsianLayout" type="CT_EastAsianLayout"/> + <xsd:element name="specVanish" type="CT_OnOff"/> + <xsd:element name="oMath" type="CT_OnOff"/> + </xsd:choice> + </xsd:group> + <xsd:group name="EG_RPrContent"> + <xsd:sequence> + <xsd:group ref="EG_RPrBase" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rPrChange" type="CT_RPrChange" minOccurs="0"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_RPr"> + <xsd:sequence> + <xsd:group ref="EG_RPrContent" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_RPr"> + <xsd:sequence> + <xsd:element name="rPr" type="CT_RPr" minOccurs="0"/> + </xsd:sequence> + </xsd:group> + <xsd:group name="EG_RPrMath"> + <xsd:choice> + <xsd:group ref="EG_RPr"/> + <xsd:element name="ins" type="CT_MathCtrlIns"/> + <xsd:element name="del" type="CT_MathCtrlDel"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_MathCtrlIns"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:choice minOccurs="0"> + <xsd:element name="del" type="CT_RPrChange" minOccurs="1"/> + <xsd:element name="rPr" type="CT_RPr" minOccurs="1"/> + </xsd:choice> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_MathCtrlDel"> + <xsd:complexContent> + <xsd:extension base="CT_TrackChange"> + <xsd:choice minOccurs="0"> + <xsd:element name="rPr" type="CT_RPr" minOccurs="1"/> + </xsd:choice> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_RPrOriginal"> + <xsd:sequence> + <xsd:group ref="EG_RPrBase" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ParaRPrOriginal"> + <xsd:sequence> + <xsd:group ref="EG_ParaRPrTrackChanges" minOccurs="0"/> + <xsd:group ref="EG_RPrBase" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ParaRPr"> + <xsd:sequence> + <xsd:group ref="EG_ParaRPrTrackChanges" minOccurs="0"/> + <xsd:group ref="EG_RPrBase" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="rPrChange" type="CT_ParaRPrChange" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_ParaRPrTrackChanges"> + <xsd:sequence> + <xsd:element name="ins" type="CT_TrackChange" minOccurs="0"/> + <xsd:element name="del" type="CT_TrackChange" minOccurs="0"/> + <xsd:element name="moveFrom" type="CT_TrackChange" minOccurs="0"/> + <xsd:element name="moveTo" type="CT_TrackChange" minOccurs="0"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_AltChunk"> + <xsd:sequence> + <xsd:element name="altChunkPr" type="CT_AltChunkPr" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute ref="r:id" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_AltChunkPr"> + <xsd:sequence> + <xsd:element name="matchSrc" type="CT_OnOff" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_RubyAlign"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="center"/> + <xsd:enumeration value="distributeLetter"/> + <xsd:enumeration value="distributeSpace"/> + <xsd:enumeration value="left"/> + <xsd:enumeration value="right"/> + <xsd:enumeration value="rightVertical"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_RubyAlign"> + <xsd:attribute name="val" type="ST_RubyAlign" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_RubyPr"> + <xsd:sequence> + <xsd:element name="rubyAlign" type="CT_RubyAlign"/> + <xsd:element name="hps" type="CT_HpsMeasure"/> + <xsd:element name="hpsRaise" type="CT_HpsMeasure"/> + <xsd:element name="hpsBaseText" type="CT_HpsMeasure"/> + <xsd:element name="lid" type="CT_Lang"/> + <xsd:element name="dirty" type="CT_OnOff" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_RubyContent"> + <xsd:choice> + <xsd:element name="r" type="CT_R"/> + <xsd:group ref="EG_RunLevelElts" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_RubyContent"> + <xsd:group ref="EG_RubyContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:complexType> + <xsd:complexType name="CT_Ruby"> + <xsd:sequence> + <xsd:element name="rubyPr" type="CT_RubyPr"/> + <xsd:element name="rt" type="CT_RubyContent"/> + <xsd:element name="rubyBase" type="CT_RubyContent"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_Lock"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="sdtLocked"/> + <xsd:enumeration value="contentLocked"/> + <xsd:enumeration value="unlocked"/> + <xsd:enumeration value="sdtContentLocked"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Lock"> + <xsd:attribute name="val" type="ST_Lock"/> + </xsd:complexType> + <xsd:complexType name="CT_SdtListItem"> + <xsd:attribute name="displayText" type="s:ST_String"/> + <xsd:attribute name="value" type="s:ST_String"/> + </xsd:complexType> + <xsd:simpleType name="ST_SdtDateMappingType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="text"/> + <xsd:enumeration value="date"/> + <xsd:enumeration value="dateTime"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SdtDateMappingType"> + <xsd:attribute name="val" type="ST_SdtDateMappingType"/> + </xsd:complexType> + <xsd:complexType name="CT_CalendarType"> + <xsd:attribute name="val" type="s:ST_CalendarType"/> + </xsd:complexType> + <xsd:complexType name="CT_SdtDate"> + <xsd:sequence> + <xsd:element name="dateFormat" type="CT_String" minOccurs="0"/> + <xsd:element name="lid" type="CT_Lang" minOccurs="0"/> + <xsd:element name="storeMappedDataAs" type="CT_SdtDateMappingType" minOccurs="0"/> + <xsd:element name="calendar" type="CT_CalendarType" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="fullDate" type="ST_DateTime" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_SdtComboBox"> + <xsd:sequence> + <xsd:element name="listItem" type="CT_SdtListItem" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="lastValue" type="s:ST_String" use="optional" default=""/> + </xsd:complexType> + <xsd:complexType name="CT_SdtDocPart"> + <xsd:sequence> + <xsd:element name="docPartGallery" type="CT_String" minOccurs="0"/> + <xsd:element name="docPartCategory" type="CT_String" minOccurs="0"/> + <xsd:element name="docPartUnique" type="CT_OnOff" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SdtDropDownList"> + <xsd:sequence> + <xsd:element name="listItem" type="CT_SdtListItem" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="lastValue" type="s:ST_String" use="optional" default=""/> + </xsd:complexType> + <xsd:complexType name="CT_Placeholder"> + <xsd:sequence> + <xsd:element name="docPart" type="CT_String"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SdtText"> + <xsd:attribute name="multiLine" type="s:ST_OnOff"/> + </xsd:complexType> + <xsd:complexType name="CT_DataBinding"> + <xsd:attribute name="prefixMappings" type="s:ST_String"/> + <xsd:attribute name="xpath" type="s:ST_String" use="required"/> + <xsd:attribute name="storeItemID" type="s:ST_String" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SdtPr"> + <xsd:sequence> + <xsd:element name="rPr" type="CT_RPr" minOccurs="0"/> + <xsd:element name="alias" type="CT_String" minOccurs="0"/> + <xsd:element name="tag" type="CT_String" minOccurs="0"/> + <xsd:element name="id" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="lock" type="CT_Lock" minOccurs="0"/> + <xsd:element name="placeholder" type="CT_Placeholder" minOccurs="0"/> + <xsd:element name="temporary" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="showingPlcHdr" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="dataBinding" type="CT_DataBinding" minOccurs="0"/> + <xsd:element name="label" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="tabIndex" type="CT_UnsignedDecimalNumber" minOccurs="0"/> + <xsd:choice minOccurs="0" maxOccurs="1"> + <xsd:element name="equation" type="CT_Empty"/> + <xsd:element name="comboBox" type="CT_SdtComboBox"/> + <xsd:element name="date" type="CT_SdtDate"/> + <xsd:element name="docPartObj" type="CT_SdtDocPart"/> + <xsd:element name="docPartList" type="CT_SdtDocPart"/> + <xsd:element name="dropDownList" type="CT_SdtDropDownList"/> + <xsd:element name="picture" type="CT_Empty"/> + <xsd:element name="richText" type="CT_Empty"/> + <xsd:element name="text" type="CT_SdtText"/> + <xsd:element name="citation" type="CT_Empty"/> + <xsd:element name="group" type="CT_Empty"/> + <xsd:element name="bibliography" type="CT_Empty"/> + </xsd:choice> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SdtEndPr"> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="rPr" type="CT_RPr" minOccurs="0"/> + </xsd:choice> + </xsd:complexType> + <xsd:group name="EG_ContentRunContent"> + <xsd:choice> + <xsd:element name="customXml" type="CT_CustomXmlRun"/> + <xsd:element name="smartTag" type="CT_SmartTagRun"/> + <xsd:element name="sdt" type="CT_SdtRun"/> + <xsd:element name="dir" type="CT_DirContentRun"/> + <xsd:element name="bdo" type="CT_BdoContentRun"/> + <xsd:element name="r" type="CT_R"/> + <xsd:group ref="EG_RunLevelElts" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_DirContentRun"> + <xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded"/> + <xsd:attribute name="val" type="ST_Direction" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_BdoContentRun"> + <xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded"/> + <xsd:attribute name="val" type="ST_Direction" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_Direction"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="ltr"/> + <xsd:enumeration value="rtl"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_SdtContentRun"> + <xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:complexType> + <xsd:group name="EG_ContentBlockContent"> + <xsd:choice> + <xsd:element name="customXml" type="CT_CustomXmlBlock"/> + <xsd:element name="sdt" type="CT_SdtBlock"/> + <xsd:element name="p" type="CT_P" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="tbl" type="CT_Tbl" minOccurs="0" maxOccurs="unbounded"/> + <xsd:group ref="EG_RunLevelElts" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_SdtContentBlock"> + <xsd:group ref="EG_ContentBlockContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:complexType> + <xsd:group name="EG_ContentRowContent"> + <xsd:choice> + <xsd:element name="tr" type="CT_Row" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="customXml" type="CT_CustomXmlRow"/> + <xsd:element name="sdt" type="CT_SdtRow"/> + <xsd:group ref="EG_RunLevelElts" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_SdtContentRow"> + <xsd:group ref="EG_ContentRowContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:complexType> + <xsd:group name="EG_ContentCellContent"> + <xsd:choice> + <xsd:element name="tc" type="CT_Tc" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="customXml" type="CT_CustomXmlCell"/> + <xsd:element name="sdt" type="CT_SdtCell"/> + <xsd:group ref="EG_RunLevelElts" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_SdtContentCell"> + <xsd:group ref="EG_ContentCellContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:complexType> + <xsd:complexType name="CT_SdtBlock"> + <xsd:sequence> + <xsd:element name="sdtPr" type="CT_SdtPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sdtEndPr" type="CT_SdtEndPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sdtContent" type="CT_SdtContentBlock" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SdtRun"> + <xsd:sequence> + <xsd:element name="sdtPr" type="CT_SdtPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sdtEndPr" type="CT_SdtEndPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sdtContent" type="CT_SdtContentRun" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SdtCell"> + <xsd:sequence> + <xsd:element name="sdtPr" type="CT_SdtPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sdtEndPr" type="CT_SdtEndPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sdtContent" type="CT_SdtContentCell" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_SdtRow"> + <xsd:sequence> + <xsd:element name="sdtPr" type="CT_SdtPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sdtEndPr" type="CT_SdtEndPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sdtContent" type="CT_SdtContentRow" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Attr"> + <xsd:attribute name="uri" type="s:ST_String"/> + <xsd:attribute name="name" type="s:ST_String" use="required"/> + <xsd:attribute name="val" type="s:ST_String" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomXmlRun"> + <xsd:sequence> + <xsd:element name="customXmlPr" type="CT_CustomXmlPr" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="uri" type="s:ST_String"/> + <xsd:attribute name="element" type="s:ST_XmlName" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SmartTagRun"> + <xsd:sequence> + <xsd:element name="smartTagPr" type="CT_SmartTagPr" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="uri" type="s:ST_String"/> + <xsd:attribute name="element" type="s:ST_XmlName" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomXmlBlock"> + <xsd:sequence> + <xsd:element name="customXmlPr" type="CT_CustomXmlPr" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_ContentBlockContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="uri" type="s:ST_String"/> + <xsd:attribute name="element" type="s:ST_XmlName" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomXmlPr"> + <xsd:sequence> + <xsd:element name="placeholder" type="CT_String" minOccurs="0"/> + <xsd:element name="attr" type="CT_Attr" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CustomXmlRow"> + <xsd:sequence> + <xsd:element name="customXmlPr" type="CT_CustomXmlPr" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_ContentRowContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="uri" type="s:ST_String"/> + <xsd:attribute name="element" type="s:ST_XmlName" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_CustomXmlCell"> + <xsd:sequence> + <xsd:element name="customXmlPr" type="CT_CustomXmlPr" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_ContentCellContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="uri" type="s:ST_String"/> + <xsd:attribute name="element" type="s:ST_XmlName" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SmartTagPr"> + <xsd:sequence> + <xsd:element name="attr" type="CT_Attr" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_PContent"> + <xsd:choice> + <xsd:group ref="EG_ContentRunContent" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="fldSimple" type="CT_SimpleField" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="hyperlink" type="CT_Hyperlink"/> + <xsd:element name="subDoc" type="CT_Rel"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_P"> + <xsd:sequence> + <xsd:element name="pPr" type="CT_PPr" minOccurs="0"/> + <xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="rsidRPr" type="ST_LongHexNumber"/> + <xsd:attribute name="rsidR" type="ST_LongHexNumber"/> + <xsd:attribute name="rsidDel" type="ST_LongHexNumber"/> + <xsd:attribute name="rsidP" type="ST_LongHexNumber"/> + <xsd:attribute name="rsidRDefault" type="ST_LongHexNumber"/> + </xsd:complexType> + <xsd:simpleType name="ST_TblWidth"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="nil"/> + <xsd:enumeration value="pct"/> + <xsd:enumeration value="dxa"/> + <xsd:enumeration value="auto"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Height"> + <xsd:attribute name="val" type="s:ST_TwipsMeasure"/> + <xsd:attribute name="hRule" type="ST_HeightRule"/> + </xsd:complexType> + <xsd:simpleType name="ST_MeasurementOrPercent"> + <xsd:union memberTypes="ST_DecimalNumberOrPercent s:ST_UniversalMeasure"/> + </xsd:simpleType> + <xsd:complexType name="CT_TblWidth"> + <xsd:attribute name="w" type="ST_MeasurementOrPercent"/> + <xsd:attribute name="type" type="ST_TblWidth"/> + </xsd:complexType> + <xsd:complexType name="CT_TblGridCol"> + <xsd:attribute name="w" type="s:ST_TwipsMeasure"/> + </xsd:complexType> + <xsd:complexType name="CT_TblGridBase"> + <xsd:sequence> + <xsd:element name="gridCol" type="CT_TblGridCol" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TblGrid"> + <xsd:complexContent> + <xsd:extension base="CT_TblGridBase"> + <xsd:sequence> + <xsd:element name="tblGridChange" type="CT_TblGridChange" minOccurs="0"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_TcBorders"> + <xsd:sequence> + <xsd:element name="top" type="CT_Border" minOccurs="0"/> + <xsd:element name="start" type="CT_Border" minOccurs="0"/> + <xsd:element name="left" type="CT_Border" minOccurs="0"/> + <xsd:element name="bottom" type="CT_Border" minOccurs="0"/> + <xsd:element name="end" type="CT_Border" minOccurs="0"/> + <xsd:element name="right" type="CT_Border" minOccurs="0"/> + <xsd:element name="insideH" type="CT_Border" minOccurs="0"/> + <xsd:element name="insideV" type="CT_Border" minOccurs="0"/> + <xsd:element name="tl2br" type="CT_Border" minOccurs="0"/> + <xsd:element name="tr2bl" type="CT_Border" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TcMar"> + <xsd:sequence> + <xsd:element name="top" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="start" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="left" type="CT_TblWidth" minOccurs="0"/> + <xsd:element name="bottom" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="end" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="right" type="CT_TblWidth" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_Merge"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="continue"/> + <xsd:enumeration value="restart"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_VMerge"> + <xsd:attribute name="val" type="ST_Merge"/> + </xsd:complexType> + <xsd:complexType name="CT_HMerge"> + <xsd:attribute name="val" type="ST_Merge"/> + </xsd:complexType> + <xsd:complexType name="CT_TcPrBase"> + <xsd:sequence> + <xsd:element name="cnfStyle" type="CT_Cnf" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tcW" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="gridSpan" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="hMerge" type="CT_HMerge" minOccurs="0"/> + <xsd:element name="vMerge" type="CT_VMerge" minOccurs="0"/> + <xsd:element name="tcBorders" type="CT_TcBorders" minOccurs="0" maxOccurs="1"/> + <xsd:element name="shd" type="CT_Shd" minOccurs="0"/> + <xsd:element name="noWrap" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="tcMar" type="CT_TcMar" minOccurs="0" maxOccurs="1"/> + <xsd:element name="textDirection" type="CT_TextDirection" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tcFitText" type="CT_OnOff" minOccurs="0" maxOccurs="1"/> + <xsd:element name="vAlign" type="CT_VerticalJc" minOccurs="0"/> + <xsd:element name="hideMark" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="headers" type="CT_Headers" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TcPr"> + <xsd:complexContent> + <xsd:extension base="CT_TcPrInner"> + <xsd:sequence> + <xsd:element name="tcPrChange" type="CT_TcPrChange" minOccurs="0"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_TcPrInner"> + <xsd:complexContent> + <xsd:extension base="CT_TcPrBase"> + <xsd:sequence> + <xsd:group ref="EG_CellMarkupElements" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_Tc"> + <xsd:sequence> + <xsd:element name="tcPr" type="CT_TcPr" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_BlockLevelElts" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="id" type="s:ST_String" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_Cnf"> + <xsd:restriction base="xsd:string"> + <xsd:length value="12"/> + <xsd:pattern value="[01]*"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Cnf"> + <xsd:attribute name="val" type="ST_Cnf"/> + <xsd:attribute name="firstRow" type="s:ST_OnOff"/> + <xsd:attribute name="lastRow" type="s:ST_OnOff"/> + <xsd:attribute name="firstColumn" type="s:ST_OnOff"/> + <xsd:attribute name="lastColumn" type="s:ST_OnOff"/> + <xsd:attribute name="oddVBand" type="s:ST_OnOff"/> + <xsd:attribute name="evenVBand" type="s:ST_OnOff"/> + <xsd:attribute name="oddHBand" type="s:ST_OnOff"/> + <xsd:attribute name="evenHBand" type="s:ST_OnOff"/> + <xsd:attribute name="firstRowFirstColumn" type="s:ST_OnOff"/> + <xsd:attribute name="firstRowLastColumn" type="s:ST_OnOff"/> + <xsd:attribute name="lastRowFirstColumn" type="s:ST_OnOff"/> + <xsd:attribute name="lastRowLastColumn" type="s:ST_OnOff"/> + </xsd:complexType> + <xsd:complexType name="CT_Headers"> + <xsd:sequence minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="header" type="CT_String"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TrPrBase"> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="cnfStyle" type="CT_Cnf" minOccurs="0" maxOccurs="1"/> + <xsd:element name="divId" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="gridBefore" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="gridAfter" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="wBefore" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="wAfter" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="cantSplit" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="trHeight" type="CT_Height" minOccurs="0"/> + <xsd:element name="tblHeader" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="tblCellSpacing" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="jc" type="CT_JcTable" minOccurs="0" maxOccurs="1"/> + <xsd:element name="hidden" type="CT_OnOff" minOccurs="0"/> + </xsd:choice> + </xsd:complexType> + <xsd:complexType name="CT_TrPr"> + <xsd:complexContent> + <xsd:extension base="CT_TrPrBase"> + <xsd:sequence> + <xsd:element name="ins" type="CT_TrackChange" minOccurs="0"/> + <xsd:element name="del" type="CT_TrackChange" minOccurs="0"/> + <xsd:element name="trPrChange" type="CT_TrPrChange" minOccurs="0"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_Row"> + <xsd:sequence> + <xsd:element name="tblPrEx" type="CT_TblPrEx" minOccurs="0" maxOccurs="1"/> + <xsd:element name="trPr" type="CT_TrPr" minOccurs="0" maxOccurs="1"/> + <xsd:group ref="EG_ContentCellContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="rsidRPr" type="ST_LongHexNumber"/> + <xsd:attribute name="rsidR" type="ST_LongHexNumber"/> + <xsd:attribute name="rsidDel" type="ST_LongHexNumber"/> + <xsd:attribute name="rsidTr" type="ST_LongHexNumber"/> + </xsd:complexType> + <xsd:simpleType name="ST_TblLayoutType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="fixed"/> + <xsd:enumeration value="autofit"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TblLayoutType"> + <xsd:attribute name="type" type="ST_TblLayoutType"/> + </xsd:complexType> + <xsd:simpleType name="ST_TblOverlap"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="never"/> + <xsd:enumeration value="overlap"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TblOverlap"> + <xsd:attribute name="val" type="ST_TblOverlap" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_TblPPr"> + <xsd:attribute name="leftFromText" type="s:ST_TwipsMeasure"/> + <xsd:attribute name="rightFromText" type="s:ST_TwipsMeasure"/> + <xsd:attribute name="topFromText" type="s:ST_TwipsMeasure"/> + <xsd:attribute name="bottomFromText" type="s:ST_TwipsMeasure"/> + <xsd:attribute name="vertAnchor" type="ST_VAnchor"/> + <xsd:attribute name="horzAnchor" type="ST_HAnchor"/> + <xsd:attribute name="tblpXSpec" type="s:ST_XAlign"/> + <xsd:attribute name="tblpX" type="ST_SignedTwipsMeasure"/> + <xsd:attribute name="tblpYSpec" type="s:ST_YAlign"/> + <xsd:attribute name="tblpY" type="ST_SignedTwipsMeasure"/> + </xsd:complexType> + <xsd:complexType name="CT_TblCellMar"> + <xsd:sequence> + <xsd:element name="top" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="start" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="left" type="CT_TblWidth" minOccurs="0"/> + <xsd:element name="bottom" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="end" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="right" type="CT_TblWidth" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TblBorders"> + <xsd:sequence> + <xsd:element name="top" type="CT_Border" minOccurs="0"/> + <xsd:element name="start" type="CT_Border" minOccurs="0"/> + <xsd:element name="left" type="CT_Border" minOccurs="0"/> + <xsd:element name="bottom" type="CT_Border" minOccurs="0"/> + <xsd:element name="end" type="CT_Border" minOccurs="0"/> + <xsd:element name="right" type="CT_Border" minOccurs="0"/> + <xsd:element name="insideH" type="CT_Border" minOccurs="0"/> + <xsd:element name="insideV" type="CT_Border" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TblPrBase"> + <xsd:sequence> + <xsd:element name="tblStyle" type="CT_String" minOccurs="0"/> + <xsd:element name="tblpPr" type="CT_TblPPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblOverlap" type="CT_TblOverlap" minOccurs="0" maxOccurs="1"/> + <xsd:element name="bidiVisual" type="CT_OnOff" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblStyleRowBandSize" type="CT_DecimalNumber" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblStyleColBandSize" type="CT_DecimalNumber" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblW" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="jc" type="CT_JcTable" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblCellSpacing" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblInd" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblBorders" type="CT_TblBorders" minOccurs="0" maxOccurs="1"/> + <xsd:element name="shd" type="CT_Shd" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblLayout" type="CT_TblLayoutType" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblCellMar" type="CT_TblCellMar" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblLook" type="CT_TblLook" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblCaption" type="CT_String" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblDescription" type="CT_String" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TblPr"> + <xsd:complexContent> + <xsd:extension base="CT_TblPrBase"> + <xsd:sequence> + <xsd:element name="tblPrChange" type="CT_TblPrChange" minOccurs="0"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_TblPrExBase"> + <xsd:sequence> + <xsd:element name="tblW" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="jc" type="CT_JcTable" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblCellSpacing" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblInd" type="CT_TblWidth" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblBorders" type="CT_TblBorders" minOccurs="0" maxOccurs="1"/> + <xsd:element name="shd" type="CT_Shd" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblLayout" type="CT_TblLayoutType" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblCellMar" type="CT_TblCellMar" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblLook" type="CT_TblLook" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TblPrEx"> + <xsd:complexContent> + <xsd:extension base="CT_TblPrExBase"> + <xsd:sequence> + <xsd:element name="tblPrExChange" type="CT_TblPrExChange" minOccurs="0"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_Tbl"> + <xsd:sequence> + <xsd:group ref="EG_RangeMarkupElements" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="tblPr" type="CT_TblPr"/> + <xsd:element name="tblGrid" type="CT_TblGrid"/> + <xsd:group ref="EG_ContentRowContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TblLook"> + <xsd:attribute name="firstRow" type="s:ST_OnOff"/> + <xsd:attribute name="lastRow" type="s:ST_OnOff"/> + <xsd:attribute name="firstColumn" type="s:ST_OnOff"/> + <xsd:attribute name="lastColumn" type="s:ST_OnOff"/> + <xsd:attribute name="noHBand" type="s:ST_OnOff"/> + <xsd:attribute name="noVBand" type="s:ST_OnOff"/> + <xsd:attribute name="val" type="ST_ShortHexNumber"/> + </xsd:complexType> + <xsd:simpleType name="ST_FtnPos"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="pageBottom"/> + <xsd:enumeration value="beneathText"/> + <xsd:enumeration value="sectEnd"/> + <xsd:enumeration value="docEnd"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_FtnPos"> + <xsd:attribute name="val" type="ST_FtnPos" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_EdnPos"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="sectEnd"/> + <xsd:enumeration value="docEnd"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_EdnPos"> + <xsd:attribute name="val" type="ST_EdnPos" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_NumFmt"> + <xsd:attribute name="val" type="ST_NumberFormat" use="required"/> + <xsd:attribute name="format" type="s:ST_String" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_RestartNumber"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="continuous"/> + <xsd:enumeration value="eachSect"/> + <xsd:enumeration value="eachPage"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_NumRestart"> + <xsd:attribute name="val" type="ST_RestartNumber" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_FtnEdnRef"> + <xsd:attribute name="customMarkFollows" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="id" use="required" type="ST_DecimalNumber"/> + </xsd:complexType> + <xsd:complexType name="CT_FtnEdnSepRef"> + <xsd:attribute name="id" type="ST_DecimalNumber" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_FtnEdn"> + <xsd:sequence> + <xsd:group ref="EG_BlockLevelElts" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="type" type="ST_FtnEdn" use="optional"/> + <xsd:attribute name="id" type="ST_DecimalNumber" use="required"/> + </xsd:complexType> + <xsd:group name="EG_FtnEdnNumProps"> + <xsd:sequence> + <xsd:element name="numStart" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="numRestart" type="CT_NumRestart" minOccurs="0"/> + </xsd:sequence> + </xsd:group> + <xsd:complexType name="CT_FtnProps"> + <xsd:sequence> + <xsd:element name="pos" type="CT_FtnPos" minOccurs="0"/> + <xsd:element name="numFmt" type="CT_NumFmt" minOccurs="0"/> + <xsd:group ref="EG_FtnEdnNumProps" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_EdnProps"> + <xsd:sequence> + <xsd:element name="pos" type="CT_EdnPos" minOccurs="0"/> + <xsd:element name="numFmt" type="CT_NumFmt" minOccurs="0"/> + <xsd:group ref="EG_FtnEdnNumProps" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_FtnDocProps"> + <xsd:complexContent> + <xsd:extension base="CT_FtnProps"> + <xsd:sequence> + <xsd:element name="footnote" type="CT_FtnEdnSepRef" minOccurs="0" maxOccurs="3"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_EdnDocProps"> + <xsd:complexContent> + <xsd:extension base="CT_EdnProps"> + <xsd:sequence> + <xsd:element name="endnote" type="CT_FtnEdnSepRef" minOccurs="0" maxOccurs="3"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_RecipientData"> + <xsd:sequence> + <xsd:element name="active" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="column" type="CT_DecimalNumber" minOccurs="1"/> + <xsd:element name="uniqueTag" type="CT_Base64Binary" minOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Base64Binary"> + <xsd:attribute name="val" type="xsd:base64Binary" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Recipients"> + <xsd:sequence> + <xsd:element name="recipientData" type="CT_RecipientData" minOccurs="1" maxOccurs="unbounded" + /> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="recipients" type="CT_Recipients"/> + <xsd:complexType name="CT_OdsoFieldMapData"> + <xsd:sequence> + <xsd:element name="type" type="CT_MailMergeOdsoFMDFieldType" minOccurs="0"/> + <xsd:element name="name" type="CT_String" minOccurs="0"/> + <xsd:element name="mappedName" type="CT_String" minOccurs="0"/> + <xsd:element name="column" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="lid" type="CT_Lang" minOccurs="0"/> + <xsd:element name="dynamicAddress" type="CT_OnOff" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_MailMergeSourceType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="database"/> + <xsd:enumeration value="addressBook"/> + <xsd:enumeration value="document1"/> + <xsd:enumeration value="document2"/> + <xsd:enumeration value="text"/> + <xsd:enumeration value="email"/> + <xsd:enumeration value="native"/> + <xsd:enumeration value="legacy"/> + <xsd:enumeration value="master"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_MailMergeSourceType"> + <xsd:attribute name="val" use="required" type="ST_MailMergeSourceType"/> + </xsd:complexType> + <xsd:complexType name="CT_Odso"> + <xsd:sequence> + <xsd:element name="udl" type="CT_String" minOccurs="0"/> + <xsd:element name="table" type="CT_String" minOccurs="0"/> + <xsd:element name="src" type="CT_Rel" minOccurs="0"/> + <xsd:element name="colDelim" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="type" type="CT_MailMergeSourceType" minOccurs="0"/> + <xsd:element name="fHdr" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="fieldMapData" type="CT_OdsoFieldMapData" minOccurs="0" + maxOccurs="unbounded"/> + <xsd:element name="recipientData" type="CT_Rel" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_MailMerge"> + <xsd:sequence> + <xsd:element name="mainDocumentType" type="CT_MailMergeDocType" minOccurs="1"/> + <xsd:element name="linkToQuery" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="dataType" type="CT_MailMergeDataType" minOccurs="1"/> + <xsd:element name="connectString" type="CT_String" minOccurs="0"/> + <xsd:element name="query" type="CT_String" minOccurs="0"/> + <xsd:element name="dataSource" type="CT_Rel" minOccurs="0"/> + <xsd:element name="headerSource" type="CT_Rel" minOccurs="0"/> + <xsd:element name="doNotSuppressBlankLines" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="destination" type="CT_MailMergeDest" minOccurs="0"/> + <xsd:element name="addressFieldName" type="CT_String" minOccurs="0"/> + <xsd:element name="mailSubject" type="CT_String" minOccurs="0"/> + <xsd:element name="mailAsAttachment" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="viewMergedData" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="activeRecord" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="checkErrors" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="odso" type="CT_Odso" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_TargetScreenSz"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="544x376"/> + <xsd:enumeration value="640x480"/> + <xsd:enumeration value="720x512"/> + <xsd:enumeration value="800x600"/> + <xsd:enumeration value="1024x768"/> + <xsd:enumeration value="1152x882"/> + <xsd:enumeration value="1152x900"/> + <xsd:enumeration value="1280x1024"/> + <xsd:enumeration value="1600x1200"/> + <xsd:enumeration value="1800x1440"/> + <xsd:enumeration value="1920x1200"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TargetScreenSz"> + <xsd:attribute name="val" type="ST_TargetScreenSz" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Compat"> + <xsd:sequence> + <xsd:element name="useSingleBorderforContiguousCells" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="wpJustification" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="noTabHangInd" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="noLeading" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="spaceForUL" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="noColumnBalance" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="balanceSingleByteDoubleByteWidth" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="noExtraLineSpacing" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotLeaveBackslashAlone" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="ulTrailSpace" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotExpandShiftReturn" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="spacingInWholePoints" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="lineWrapLikeWord6" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="printBodyTextBeforeHeader" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="printColBlack" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="wpSpaceWidth" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="showBreaksInFrames" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="subFontBySize" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="suppressBottomSpacing" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="suppressTopSpacing" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="suppressSpacingAtTopOfPage" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="suppressTopSpacingWP" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="suppressSpBfAfterPgBrk" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="swapBordersFacingPages" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="convMailMergeEsc" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="truncateFontHeightsLikeWP6" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="mwSmallCaps" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="usePrinterMetrics" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotSuppressParagraphBorders" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="wrapTrailSpaces" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="footnoteLayoutLikeWW8" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="shapeLayoutLikeWW8" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="alignTablesRowByRow" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="forgetLastTabAlignment" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="adjustLineHeightInTable" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="autoSpaceLikeWord95" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="noSpaceRaiseLower" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotUseHTMLParagraphAutoSpacing" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="layoutRawTableWidth" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="layoutTableRowsApart" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="useWord97LineBreakRules" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotBreakWrappedTables" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotSnapToGridInCell" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="selectFldWithFirstOrLastChar" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="applyBreakingRules" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotWrapTextWithPunct" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotUseEastAsianBreakRules" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="useWord2002TableStyleRules" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="growAutofit" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="useFELayout" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="useNormalStyleForList" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotUseIndentAsNumberingTabStop" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="useAltKinsokuLineBreakRules" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="allowSpaceOfSameStyleInTable" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotSuppressIndentation" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotAutofitConstrainedTables" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="autofitToFirstFixedWidthCell" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="underlineTabInNumList" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="displayHangulFixedWidth" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="splitPgBreakAndParaMark" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotVertAlignCellWithSp" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotBreakConstrainedForcedTable" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotVertAlignInTxbx" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="useAnsiKerningPairs" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="cachedColBalance" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="compatSetting" type="CT_CompatSetting" minOccurs="0" maxOccurs="unbounded" + /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CompatSetting"> + <xsd:attribute name="name" type="s:ST_String"/> + <xsd:attribute name="uri" type="s:ST_String"/> + <xsd:attribute name="val" type="s:ST_String"/> + </xsd:complexType> + <xsd:complexType name="CT_DocVar"> + <xsd:attribute name="name" type="s:ST_String" use="required"/> + <xsd:attribute name="val" type="s:ST_String" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_DocVars"> + <xsd:sequence> + <xsd:element name="docVar" type="CT_DocVar" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DocRsids"> + <xsd:sequence> + <xsd:element name="rsidRoot" type="CT_LongHexNumber" minOccurs="0" maxOccurs="1"/> + <xsd:element name="rsid" type="CT_LongHexNumber" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_CharacterSpacing"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="doNotCompress"/> + <xsd:enumeration value="compressPunctuation"/> + <xsd:enumeration value="compressPunctuationAndJapaneseKana"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_CharacterSpacing"> + <xsd:attribute name="val" type="ST_CharacterSpacing" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SaveThroughXslt"> + <xsd:attribute ref="r:id" use="optional"/> + <xsd:attribute name="solutionID" type="s:ST_String" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_RPrDefault"> + <xsd:sequence> + <xsd:element name="rPr" type="CT_RPr" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PPrDefault"> + <xsd:sequence> + <xsd:element name="pPr" type="CT_PPrGeneral" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DocDefaults"> + <xsd:sequence> + <xsd:element name="rPrDefault" type="CT_RPrDefault" minOccurs="0"/> + <xsd:element name="pPrDefault" type="CT_PPrDefault" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_WmlColorSchemeIndex"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="dark1"/> + <xsd:enumeration value="light1"/> + <xsd:enumeration value="dark2"/> + <xsd:enumeration value="light2"/> + <xsd:enumeration value="accent1"/> + <xsd:enumeration value="accent2"/> + <xsd:enumeration value="accent3"/> + <xsd:enumeration value="accent4"/> + <xsd:enumeration value="accent5"/> + <xsd:enumeration value="accent6"/> + <xsd:enumeration value="hyperlink"/> + <xsd:enumeration value="followedHyperlink"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_ColorSchemeMapping"> + <xsd:attribute name="bg1" type="ST_WmlColorSchemeIndex"/> + <xsd:attribute name="t1" type="ST_WmlColorSchemeIndex"/> + <xsd:attribute name="bg2" type="ST_WmlColorSchemeIndex"/> + <xsd:attribute name="t2" type="ST_WmlColorSchemeIndex"/> + <xsd:attribute name="accent1" type="ST_WmlColorSchemeIndex"/> + <xsd:attribute name="accent2" type="ST_WmlColorSchemeIndex"/> + <xsd:attribute name="accent3" type="ST_WmlColorSchemeIndex"/> + <xsd:attribute name="accent4" type="ST_WmlColorSchemeIndex"/> + <xsd:attribute name="accent5" type="ST_WmlColorSchemeIndex"/> + <xsd:attribute name="accent6" type="ST_WmlColorSchemeIndex"/> + <xsd:attribute name="hyperlink" type="ST_WmlColorSchemeIndex"/> + <xsd:attribute name="followedHyperlink" type="ST_WmlColorSchemeIndex"/> + </xsd:complexType> + <xsd:complexType name="CT_ReadingModeInkLockDown"> + <xsd:attribute name="actualPg" type="s:ST_OnOff" use="required"/> + <xsd:attribute name="w" type="ST_PixelsMeasure" use="required"/> + <xsd:attribute name="h" type="ST_PixelsMeasure" use="required"/> + <xsd:attribute name="fontSz" type="ST_DecimalNumberOrPercent" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_WriteProtection"> + <xsd:attribute name="recommended" type="s:ST_OnOff" use="optional"/> + <xsd:attributeGroup ref="AG_Password"/> + <xsd:attributeGroup ref="AG_TransitionalPassword"/> + </xsd:complexType> + <xsd:complexType name="CT_Settings"> + <xsd:sequence> + <xsd:element name="writeProtection" type="CT_WriteProtection" minOccurs="0"/> + <xsd:element name="view" type="CT_View" minOccurs="0"/> + <xsd:element name="zoom" type="CT_Zoom" minOccurs="0"/> + <xsd:element name="removePersonalInformation" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="removeDateAndTime" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotDisplayPageBoundaries" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="displayBackgroundShape" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="printPostScriptOverText" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="printFractionalCharacterWidth" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="printFormsData" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="embedTrueTypeFonts" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="embedSystemFonts" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="saveSubsetFonts" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="saveFormsData" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="mirrorMargins" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="alignBordersAndEdges" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="bordersDoNotSurroundHeader" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="bordersDoNotSurroundFooter" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="gutterAtTop" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="hideSpellingErrors" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="hideGrammaticalErrors" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="activeWritingStyle" type="CT_WritingStyle" minOccurs="0" + maxOccurs="unbounded"/> + <xsd:element name="proofState" type="CT_Proof" minOccurs="0"/> + <xsd:element name="formsDesign" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="attachedTemplate" type="CT_Rel" minOccurs="0"/> + <xsd:element name="linkStyles" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="stylePaneFormatFilter" type="CT_StylePaneFilter" minOccurs="0"/> + <xsd:element name="stylePaneSortMethod" type="CT_StyleSort" minOccurs="0"/> + <xsd:element name="documentType" type="CT_DocType" minOccurs="0"/> + <xsd:element name="mailMerge" type="CT_MailMerge" minOccurs="0"/> + <xsd:element name="revisionView" type="CT_TrackChangesView" minOccurs="0"/> + <xsd:element name="trackRevisions" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotTrackMoves" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotTrackFormatting" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="documentProtection" type="CT_DocProtect" minOccurs="0"/> + <xsd:element name="autoFormatOverride" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="styleLockTheme" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="styleLockQFSet" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="defaultTabStop" type="CT_TwipsMeasure" minOccurs="0"/> + <xsd:element name="autoHyphenation" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="consecutiveHyphenLimit" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="hyphenationZone" type="CT_TwipsMeasure" minOccurs="0"/> + <xsd:element name="doNotHyphenateCaps" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="showEnvelope" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="summaryLength" type="CT_DecimalNumberOrPrecent" minOccurs="0"/> + <xsd:element name="clickAndTypeStyle" type="CT_String" minOccurs="0"/> + <xsd:element name="defaultTableStyle" type="CT_String" minOccurs="0"/> + <xsd:element name="evenAndOddHeaders" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="bookFoldRevPrinting" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="bookFoldPrinting" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="bookFoldPrintingSheets" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="drawingGridHorizontalSpacing" type="CT_TwipsMeasure" minOccurs="0"/> + <xsd:element name="drawingGridVerticalSpacing" type="CT_TwipsMeasure" minOccurs="0"/> + <xsd:element name="displayHorizontalDrawingGridEvery" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="displayVerticalDrawingGridEvery" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="doNotUseMarginsForDrawingGridOrigin" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="drawingGridHorizontalOrigin" type="CT_TwipsMeasure" minOccurs="0"/> + <xsd:element name="drawingGridVerticalOrigin" type="CT_TwipsMeasure" minOccurs="0"/> + <xsd:element name="doNotShadeFormData" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="noPunctuationKerning" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="characterSpacingControl" type="CT_CharacterSpacing" minOccurs="0"/> + <xsd:element name="printTwoOnOne" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="strictFirstAndLastChars" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="noLineBreaksAfter" type="CT_Kinsoku" minOccurs="0"/> + <xsd:element name="noLineBreaksBefore" type="CT_Kinsoku" minOccurs="0"/> + <xsd:element name="savePreviewPicture" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotValidateAgainstSchema" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="saveInvalidXml" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="ignoreMixedContent" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="alwaysShowPlaceholderText" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotDemarcateInvalidXml" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="saveXmlDataOnly" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="useXSLTWhenSaving" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="saveThroughXslt" type="CT_SaveThroughXslt" minOccurs="0"/> + <xsd:element name="showXMLTags" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="alwaysMergeEmptyNamespace" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="updateFields" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="hdrShapeDefaults" type="CT_ShapeDefaults" minOccurs="0"/> + <xsd:element name="footnotePr" type="CT_FtnDocProps" minOccurs="0"/> + <xsd:element name="endnotePr" type="CT_EdnDocProps" minOccurs="0"/> + <xsd:element name="compat" type="CT_Compat" minOccurs="0"/> + <xsd:element name="docVars" type="CT_DocVars" minOccurs="0"/> + <xsd:element name="rsids" type="CT_DocRsids" minOccurs="0"/> + <xsd:element ref="m:mathPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="attachedSchema" type="CT_String" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="themeFontLang" type="CT_Language" minOccurs="0" maxOccurs="1"/> + <xsd:element name="clrSchemeMapping" type="CT_ColorSchemeMapping" minOccurs="0"/> + <xsd:element name="doNotIncludeSubdocsInStats" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotAutoCompressPictures" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="forceUpgrade" type="CT_Empty" minOccurs="0" maxOccurs="1"/> + <xsd:element name="captions" type="CT_Captions" minOccurs="0" maxOccurs="1"/> + <xsd:element name="readModeInkLockDown" type="CT_ReadingModeInkLockDown" minOccurs="0"/> + <xsd:element name="smartTagType" type="CT_SmartTagType" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element ref="sl:schemaLibrary" minOccurs="0" maxOccurs="1"/> + <xsd:element name="shapeDefaults" type="CT_ShapeDefaults" minOccurs="0"/> + <xsd:element name="doNotEmbedSmartTags" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="decimalSymbol" type="CT_String" minOccurs="0" maxOccurs="1"/> + <xsd:element name="listSeparator" type="CT_String" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_StyleSort"> + <xsd:attribute name="val" type="ST_StyleSort" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_StylePaneFilter"> + <xsd:attribute name="allStyles" type="s:ST_OnOff"/> + <xsd:attribute name="customStyles" type="s:ST_OnOff"/> + <xsd:attribute name="latentStyles" type="s:ST_OnOff"/> + <xsd:attribute name="stylesInUse" type="s:ST_OnOff"/> + <xsd:attribute name="headingStyles" type="s:ST_OnOff"/> + <xsd:attribute name="numberingStyles" type="s:ST_OnOff"/> + <xsd:attribute name="tableStyles" type="s:ST_OnOff"/> + <xsd:attribute name="directFormattingOnRuns" type="s:ST_OnOff"/> + <xsd:attribute name="directFormattingOnParagraphs" type="s:ST_OnOff"/> + <xsd:attribute name="directFormattingOnNumbering" type="s:ST_OnOff"/> + <xsd:attribute name="directFormattingOnTables" type="s:ST_OnOff"/> + <xsd:attribute name="clearFormatting" type="s:ST_OnOff"/> + <xsd:attribute name="top3HeadingStyles" type="s:ST_OnOff"/> + <xsd:attribute name="visibleStyles" type="s:ST_OnOff"/> + <xsd:attribute name="alternateStyleNames" type="s:ST_OnOff"/> + <xsd:attribute name="val" type="ST_ShortHexNumber"/> + </xsd:complexType> + <xsd:simpleType name="ST_StyleSort"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="name"/> + <xsd:enumeration value="priority"/> + <xsd:enumeration value="default"/> + <xsd:enumeration value="font"/> + <xsd:enumeration value="basedOn"/> + <xsd:enumeration value="type"/> + <xsd:enumeration value="0000"/> + <xsd:enumeration value="0001"/> + <xsd:enumeration value="0002"/> + <xsd:enumeration value="0003"/> + <xsd:enumeration value="0004"/> + <xsd:enumeration value="0005"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_WebSettings"> + <xsd:sequence> + <xsd:element name="frameset" type="CT_Frameset" minOccurs="0"/> + <xsd:element name="divs" type="CT_Divs" minOccurs="0"/> + <xsd:element name="encoding" type="CT_String" minOccurs="0"/> + <xsd:element name="optimizeForBrowser" type="CT_OptimizeForBrowser" minOccurs="0"/> + <xsd:element name="relyOnVML" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="allowPNG" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotRelyOnCSS" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotSaveAsSingleFile" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotOrganizeInFolder" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="doNotUseLongFileNames" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="pixelsPerInch" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="targetScreenSz" type="CT_TargetScreenSz" minOccurs="0"/> + <xsd:element name="saveSmartTagsAsXml" type="CT_OnOff" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_FrameScrollbar"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="on"/> + <xsd:enumeration value="off"/> + <xsd:enumeration value="auto"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_FrameScrollbar"> + <xsd:attribute name="val" type="ST_FrameScrollbar" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_OptimizeForBrowser"> + <xsd:complexContent> + <xsd:extension base="CT_OnOff"> + <xsd:attribute name="target" type="s:ST_String" use="optional"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_Frame"> + <xsd:sequence> + <xsd:element name="sz" type="CT_String" minOccurs="0"/> + <xsd:element name="name" type="CT_String" minOccurs="0"/> + <xsd:element name="title" type="CT_String" minOccurs="0"/> + <xsd:element name="longDesc" type="CT_Rel" minOccurs="0"/> + <xsd:element name="sourceFileName" type="CT_Rel" minOccurs="0"/> + <xsd:element name="marW" type="CT_PixelsMeasure" minOccurs="0"/> + <xsd:element name="marH" type="CT_PixelsMeasure" minOccurs="0"/> + <xsd:element name="scrollbar" type="CT_FrameScrollbar" minOccurs="0"/> + <xsd:element name="noResizeAllowed" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="linkedToFile" type="CT_OnOff" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_FrameLayout"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="rows"/> + <xsd:enumeration value="cols"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_FrameLayout"> + <xsd:attribute name="val" type="ST_FrameLayout" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_FramesetSplitbar"> + <xsd:sequence> + <xsd:element name="w" type="CT_TwipsMeasure" minOccurs="0"/> + <xsd:element name="color" type="CT_Color" minOccurs="0"/> + <xsd:element name="noBorder" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="flatBorders" type="CT_OnOff" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Frameset"> + <xsd:sequence> + <xsd:element name="sz" type="CT_String" minOccurs="0"/> + <xsd:element name="framesetSplitbar" type="CT_FramesetSplitbar" minOccurs="0"/> + <xsd:element name="frameLayout" type="CT_FrameLayout" minOccurs="0"/> + <xsd:element name="title" type="CT_String" minOccurs="0"/> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="frameset" type="CT_Frameset" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="frame" type="CT_Frame" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_NumPicBullet"> + <xsd:choice> + <xsd:element name="pict" type="CT_Picture"/> + <xsd:element name="drawing" type="CT_Drawing"/> + </xsd:choice> + <xsd:attribute name="numPicBulletId" type="ST_DecimalNumber" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_LevelSuffix"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="tab"/> + <xsd:enumeration value="space"/> + <xsd:enumeration value="nothing"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_LevelSuffix"> + <xsd:attribute name="val" type="ST_LevelSuffix" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_LevelText"> + <xsd:attribute name="val" type="s:ST_String" use="optional"/> + <xsd:attribute name="null" type="s:ST_OnOff" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_LvlLegacy"> + <xsd:attribute name="legacy" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="legacySpace" type="s:ST_TwipsMeasure" use="optional"/> + <xsd:attribute name="legacyIndent" type="ST_SignedTwipsMeasure" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_Lvl"> + <xsd:sequence> + <xsd:element name="start" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="numFmt" type="CT_NumFmt" minOccurs="0"/> + <xsd:element name="lvlRestart" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="pStyle" type="CT_String" minOccurs="0"/> + <xsd:element name="isLgl" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="suff" type="CT_LevelSuffix" minOccurs="0"/> + <xsd:element name="lvlText" type="CT_LevelText" minOccurs="0"/> + <xsd:element name="lvlPicBulletId" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="legacy" type="CT_LvlLegacy" minOccurs="0"/> + <xsd:element name="lvlJc" type="CT_Jc" minOccurs="0"/> + <xsd:element name="pPr" type="CT_PPrGeneral" minOccurs="0"/> + <xsd:element name="rPr" type="CT_RPr" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="ilvl" type="ST_DecimalNumber" use="required"/> + <xsd:attribute name="tplc" type="ST_LongHexNumber" use="optional"/> + <xsd:attribute name="tentative" type="s:ST_OnOff" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_MultiLevelType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="singleLevel"/> + <xsd:enumeration value="multilevel"/> + <xsd:enumeration value="hybridMultilevel"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_MultiLevelType"> + <xsd:attribute name="val" type="ST_MultiLevelType" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_AbstractNum"> + <xsd:sequence> + <xsd:element name="nsid" type="CT_LongHexNumber" minOccurs="0"/> + <xsd:element name="multiLevelType" type="CT_MultiLevelType" minOccurs="0"/> + <xsd:element name="tmpl" type="CT_LongHexNumber" minOccurs="0"/> + <xsd:element name="name" type="CT_String" minOccurs="0"/> + <xsd:element name="styleLink" type="CT_String" minOccurs="0"/> + <xsd:element name="numStyleLink" type="CT_String" minOccurs="0"/> + <xsd:element name="lvl" type="CT_Lvl" minOccurs="0" maxOccurs="9"/> + </xsd:sequence> + <xsd:attribute name="abstractNumId" type="ST_DecimalNumber" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_NumLvl"> + <xsd:sequence> + <xsd:element name="startOverride" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="lvl" type="CT_Lvl" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="ilvl" type="ST_DecimalNumber" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Num"> + <xsd:sequence> + <xsd:element name="abstractNumId" type="CT_DecimalNumber" minOccurs="1"/> + <xsd:element name="lvlOverride" type="CT_NumLvl" minOccurs="0" maxOccurs="9"/> + </xsd:sequence> + <xsd:attribute name="numId" type="ST_DecimalNumber" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Numbering"> + <xsd:sequence> + <xsd:element name="numPicBullet" type="CT_NumPicBullet" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="abstractNum" type="CT_AbstractNum" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="num" type="CT_Num" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="numIdMacAtCleanup" type="CT_DecimalNumber" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_TblStyleOverrideType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="wholeTable"/> + <xsd:enumeration value="firstRow"/> + <xsd:enumeration value="lastRow"/> + <xsd:enumeration value="firstCol"/> + <xsd:enumeration value="lastCol"/> + <xsd:enumeration value="band1Vert"/> + <xsd:enumeration value="band2Vert"/> + <xsd:enumeration value="band1Horz"/> + <xsd:enumeration value="band2Horz"/> + <xsd:enumeration value="neCell"/> + <xsd:enumeration value="nwCell"/> + <xsd:enumeration value="seCell"/> + <xsd:enumeration value="swCell"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_TblStylePr"> + <xsd:sequence> + <xsd:element name="pPr" type="CT_PPrGeneral" minOccurs="0"/> + <xsd:element name="rPr" type="CT_RPr" minOccurs="0"/> + <xsd:element name="tblPr" type="CT_TblPrBase" minOccurs="0"/> + <xsd:element name="trPr" type="CT_TrPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tcPr" type="CT_TcPr" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="type" type="ST_TblStyleOverrideType" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_StyleType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="paragraph"/> + <xsd:enumeration value="character"/> + <xsd:enumeration value="table"/> + <xsd:enumeration value="numbering"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Style"> + <xsd:sequence> + <xsd:element name="name" type="CT_String" minOccurs="0" maxOccurs="1"/> + <xsd:element name="aliases" type="CT_String" minOccurs="0"/> + <xsd:element name="basedOn" type="CT_String" minOccurs="0"/> + <xsd:element name="next" type="CT_String" minOccurs="0"/> + <xsd:element name="link" type="CT_String" minOccurs="0"/> + <xsd:element name="autoRedefine" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="hidden" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="uiPriority" type="CT_DecimalNumber" minOccurs="0"/> + <xsd:element name="semiHidden" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="unhideWhenUsed" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="qFormat" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="locked" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="personal" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="personalCompose" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="personalReply" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="rsid" type="CT_LongHexNumber" minOccurs="0"/> + <xsd:element name="pPr" type="CT_PPrGeneral" minOccurs="0" maxOccurs="1"/> + <xsd:element name="rPr" type="CT_RPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblPr" type="CT_TblPrBase" minOccurs="0" maxOccurs="1"/> + <xsd:element name="trPr" type="CT_TrPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tcPr" type="CT_TcPr" minOccurs="0" maxOccurs="1"/> + <xsd:element name="tblStylePr" type="CT_TblStylePr" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="type" type="ST_StyleType" use="optional"/> + <xsd:attribute name="styleId" type="s:ST_String" use="optional"/> + <xsd:attribute name="default" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="customStyle" type="s:ST_OnOff" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_LsdException"> + <xsd:attribute name="name" type="s:ST_String" use="required"/> + <xsd:attribute name="locked" type="s:ST_OnOff"/> + <xsd:attribute name="uiPriority" type="ST_DecimalNumber"/> + <xsd:attribute name="semiHidden" type="s:ST_OnOff"/> + <xsd:attribute name="unhideWhenUsed" type="s:ST_OnOff"/> + <xsd:attribute name="qFormat" type="s:ST_OnOff"/> + </xsd:complexType> + <xsd:complexType name="CT_LatentStyles"> + <xsd:sequence> + <xsd:element name="lsdException" type="CT_LsdException" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="defLockedState" type="s:ST_OnOff"/> + <xsd:attribute name="defUIPriority" type="ST_DecimalNumber"/> + <xsd:attribute name="defSemiHidden" type="s:ST_OnOff"/> + <xsd:attribute name="defUnhideWhenUsed" type="s:ST_OnOff"/> + <xsd:attribute name="defQFormat" type="s:ST_OnOff"/> + <xsd:attribute name="count" type="ST_DecimalNumber"/> + </xsd:complexType> + <xsd:complexType name="CT_Styles"> + <xsd:sequence> + <xsd:element name="docDefaults" type="CT_DocDefaults" minOccurs="0"/> + <xsd:element name="latentStyles" type="CT_LatentStyles" minOccurs="0" maxOccurs="1"/> + <xsd:element name="style" type="CT_Style" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Panose"> + <xsd:attribute name="val" type="s:ST_Panose" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_FontFamily"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="decorative"/> + <xsd:enumeration value="modern"/> + <xsd:enumeration value="roman"/> + <xsd:enumeration value="script"/> + <xsd:enumeration value="swiss"/> + <xsd:enumeration value="auto"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_FontFamily"> + <xsd:attribute name="val" type="ST_FontFamily" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_Pitch"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="fixed"/> + <xsd:enumeration value="variable"/> + <xsd:enumeration value="default"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Pitch"> + <xsd:attribute name="val" type="ST_Pitch" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_FontSig"> + <xsd:attribute name="usb0" use="required" type="ST_LongHexNumber"/> + <xsd:attribute name="usb1" use="required" type="ST_LongHexNumber"/> + <xsd:attribute name="usb2" use="required" type="ST_LongHexNumber"/> + <xsd:attribute name="usb3" use="required" type="ST_LongHexNumber"/> + <xsd:attribute name="csb0" use="required" type="ST_LongHexNumber"/> + <xsd:attribute name="csb1" use="required" type="ST_LongHexNumber"/> + </xsd:complexType> + <xsd:complexType name="CT_FontRel"> + <xsd:complexContent> + <xsd:extension base="CT_Rel"> + <xsd:attribute name="fontKey" type="s:ST_Guid"/> + <xsd:attribute name="subsetted" type="s:ST_OnOff"/> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_Font"> + <xsd:sequence> + <xsd:element name="altName" type="CT_String" minOccurs="0" maxOccurs="1"/> + <xsd:element name="panose1" type="CT_Panose" minOccurs="0" maxOccurs="1"/> + <xsd:element name="charset" type="CT_Charset" minOccurs="0" maxOccurs="1"/> + <xsd:element name="family" type="CT_FontFamily" minOccurs="0" maxOccurs="1"/> + <xsd:element name="notTrueType" type="CT_OnOff" minOccurs="0" maxOccurs="1"/> + <xsd:element name="pitch" type="CT_Pitch" minOccurs="0" maxOccurs="1"/> + <xsd:element name="sig" type="CT_FontSig" minOccurs="0" maxOccurs="1"/> + <xsd:element name="embedRegular" type="CT_FontRel" minOccurs="0" maxOccurs="1"/> + <xsd:element name="embedBold" type="CT_FontRel" minOccurs="0" maxOccurs="1"/> + <xsd:element name="embedItalic" type="CT_FontRel" minOccurs="0" maxOccurs="1"/> + <xsd:element name="embedBoldItalic" type="CT_FontRel" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="name" type="s:ST_String" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_FontsList"> + <xsd:sequence> + <xsd:element name="font" type="CT_Font" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DivBdr"> + <xsd:sequence> + <xsd:element name="top" type="CT_Border" minOccurs="0"/> + <xsd:element name="left" type="CT_Border" minOccurs="0"/> + <xsd:element name="bottom" type="CT_Border" minOccurs="0"/> + <xsd:element name="right" type="CT_Border" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Div"> + <xsd:sequence> + <xsd:element name="blockQuote" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="bodyDiv" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="marLeft" type="CT_SignedTwipsMeasure"/> + <xsd:element name="marRight" type="CT_SignedTwipsMeasure"/> + <xsd:element name="marTop" type="CT_SignedTwipsMeasure"/> + <xsd:element name="marBottom" type="CT_SignedTwipsMeasure"/> + <xsd:element name="divBdr" type="CT_DivBdr" minOccurs="0"/> + <xsd:element name="divsChild" type="CT_Divs" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="id" type="ST_DecimalNumber" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Divs"> + <xsd:sequence minOccurs="1" maxOccurs="unbounded"> + <xsd:element name="div" type="CT_Div"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TxbxContent"> + <xsd:group ref="EG_BlockLevelElts" minOccurs="1" maxOccurs="unbounded"/> + </xsd:complexType> + <xsd:element name="txbxContent" type="CT_TxbxContent"/> + <xsd:group name="EG_MathContent"> + <xsd:choice> + <xsd:element ref="m:oMathPara"/> + <xsd:element ref="m:oMath"/> + </xsd:choice> + </xsd:group> + <xsd:group name="EG_BlockLevelChunkElts"> + <xsd:choice> + <xsd:group ref="EG_ContentBlockContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:group> + <xsd:group name="EG_BlockLevelElts"> + <xsd:choice> + <xsd:group ref="EG_BlockLevelChunkElts" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="altChunk" type="CT_AltChunk" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:group> + <xsd:group name="EG_RunLevelElts"> + <xsd:choice> + <xsd:element name="proofErr" minOccurs="0" type="CT_ProofErr"/> + <xsd:element name="permStart" minOccurs="0" type="CT_PermStart"/> + <xsd:element name="permEnd" minOccurs="0" type="CT_Perm"/> + <xsd:group ref="EG_RangeMarkupElements" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="ins" type="CT_RunTrackChange" minOccurs="0"/> + <xsd:element name="del" type="CT_RunTrackChange" minOccurs="0"/> + <xsd:element name="moveFrom" type="CT_RunTrackChange"/> + <xsd:element name="moveTo" type="CT_RunTrackChange"/> + <xsd:group ref="EG_MathContent" minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_Body"> + <xsd:sequence> + <xsd:group ref="EG_BlockLevelElts" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="sectPr" minOccurs="0" maxOccurs="1" type="CT_SectPr"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_ShapeDefaults"> + <xsd:choice maxOccurs="unbounded"> + <xsd:any processContents="lax" namespace="urn:schemas-microsoft-com:office:office" + minOccurs="0" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:complexType> + <xsd:complexType name="CT_Comments"> + <xsd:sequence> + <xsd:element name="comment" type="CT_Comment" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="comments" type="CT_Comments"/> + <xsd:complexType name="CT_Footnotes"> + <xsd:sequence maxOccurs="unbounded"> + <xsd:element name="footnote" type="CT_FtnEdn" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="footnotes" type="CT_Footnotes"/> + <xsd:complexType name="CT_Endnotes"> + <xsd:sequence maxOccurs="unbounded"> + <xsd:element name="endnote" type="CT_FtnEdn" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="endnotes" type="CT_Endnotes"/> + <xsd:element name="hdr" type="CT_HdrFtr"/> + <xsd:element name="ftr" type="CT_HdrFtr"/> + <xsd:complexType name="CT_SmartTagType"> + <xsd:attribute name="namespaceuri" type="s:ST_String"/> + <xsd:attribute name="name" type="s:ST_String"/> + <xsd:attribute name="url" type="s:ST_String"/> + </xsd:complexType> + <xsd:simpleType name="ST_ThemeColor"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="dark1"/> + <xsd:enumeration value="light1"/> + <xsd:enumeration value="dark2"/> + <xsd:enumeration value="light2"/> + <xsd:enumeration value="accent1"/> + <xsd:enumeration value="accent2"/> + <xsd:enumeration value="accent3"/> + <xsd:enumeration value="accent4"/> + <xsd:enumeration value="accent5"/> + <xsd:enumeration value="accent6"/> + <xsd:enumeration value="hyperlink"/> + <xsd:enumeration value="followedHyperlink"/> + <xsd:enumeration value="none"/> + <xsd:enumeration value="background1"/> + <xsd:enumeration value="text1"/> + <xsd:enumeration value="background2"/> + <xsd:enumeration value="text2"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_DocPartBehavior"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="content"/> + <xsd:enumeration value="p"/> + <xsd:enumeration value="pg"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_DocPartBehavior"> + <xsd:attribute name="val" use="required" type="ST_DocPartBehavior"/> + </xsd:complexType> + <xsd:complexType name="CT_DocPartBehaviors"> + <xsd:choice> + <xsd:element name="behavior" type="CT_DocPartBehavior" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:complexType> + <xsd:simpleType name="ST_DocPartType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="normal"/> + <xsd:enumeration value="autoExp"/> + <xsd:enumeration value="toolbar"/> + <xsd:enumeration value="speller"/> + <xsd:enumeration value="formFld"/> + <xsd:enumeration value="bbPlcHdr"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_DocPartType"> + <xsd:attribute name="val" use="required" type="ST_DocPartType"/> + </xsd:complexType> + <xsd:complexType name="CT_DocPartTypes"> + <xsd:choice> + <xsd:element name="type" type="CT_DocPartType" maxOccurs="unbounded"/> + </xsd:choice> + <xsd:attribute name="all" type="s:ST_OnOff" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_DocPartGallery"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="placeholder"/> + <xsd:enumeration value="any"/> + <xsd:enumeration value="default"/> + <xsd:enumeration value="docParts"/> + <xsd:enumeration value="coverPg"/> + <xsd:enumeration value="eq"/> + <xsd:enumeration value="ftrs"/> + <xsd:enumeration value="hdrs"/> + <xsd:enumeration value="pgNum"/> + <xsd:enumeration value="tbls"/> + <xsd:enumeration value="watermarks"/> + <xsd:enumeration value="autoTxt"/> + <xsd:enumeration value="txtBox"/> + <xsd:enumeration value="pgNumT"/> + <xsd:enumeration value="pgNumB"/> + <xsd:enumeration value="pgNumMargins"/> + <xsd:enumeration value="tblOfContents"/> + <xsd:enumeration value="bib"/> + <xsd:enumeration value="custQuickParts"/> + <xsd:enumeration value="custCoverPg"/> + <xsd:enumeration value="custEq"/> + <xsd:enumeration value="custFtrs"/> + <xsd:enumeration value="custHdrs"/> + <xsd:enumeration value="custPgNum"/> + <xsd:enumeration value="custTbls"/> + <xsd:enumeration value="custWatermarks"/> + <xsd:enumeration value="custAutoTxt"/> + <xsd:enumeration value="custTxtBox"/> + <xsd:enumeration value="custPgNumT"/> + <xsd:enumeration value="custPgNumB"/> + <xsd:enumeration value="custPgNumMargins"/> + <xsd:enumeration value="custTblOfContents"/> + <xsd:enumeration value="custBib"/> + <xsd:enumeration value="custom1"/> + <xsd:enumeration value="custom2"/> + <xsd:enumeration value="custom3"/> + <xsd:enumeration value="custom4"/> + <xsd:enumeration value="custom5"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_DocPartGallery"> + <xsd:attribute name="val" type="ST_DocPartGallery" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_DocPartCategory"> + <xsd:sequence> + <xsd:element name="name" type="CT_String" minOccurs="1" maxOccurs="1"/> + <xsd:element name="gallery" type="CT_DocPartGallery" minOccurs="1" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DocPartName"> + <xsd:attribute name="val" type="s:ST_String" use="required"/> + <xsd:attribute name="decorated" type="s:ST_OnOff" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_DocPartPr"> + <xsd:all> + <xsd:element name="name" type="CT_DocPartName" minOccurs="1"/> + <xsd:element name="style" type="CT_String" minOccurs="0"/> + <xsd:element name="category" type="CT_DocPartCategory" minOccurs="0"/> + <xsd:element name="types" type="CT_DocPartTypes" minOccurs="0"/> + <xsd:element name="behaviors" type="CT_DocPartBehaviors" minOccurs="0"/> + <xsd:element name="description" type="CT_String" minOccurs="0"/> + <xsd:element name="guid" type="CT_Guid" minOccurs="0"/> + </xsd:all> + </xsd:complexType> + <xsd:complexType name="CT_DocPart"> + <xsd:sequence> + <xsd:element name="docPartPr" type="CT_DocPartPr" minOccurs="0"/> + <xsd:element name="docPartBody" type="CT_Body" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DocParts"> + <xsd:choice> + <xsd:element name="docPart" type="CT_DocPart" minOccurs="1" maxOccurs="unbounded"/> + </xsd:choice> + </xsd:complexType> + <xsd:element name="settings" type="CT_Settings"/> + <xsd:element name="webSettings" type="CT_WebSettings"/> + <xsd:element name="fonts" type="CT_FontsList"/> + <xsd:element name="numbering" type="CT_Numbering"/> + <xsd:element name="styles" type="CT_Styles"/> + <xsd:simpleType name="ST_CaptionPos"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="above"/> + <xsd:enumeration value="below"/> + <xsd:enumeration value="left"/> + <xsd:enumeration value="right"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Caption"> + <xsd:attribute name="name" type="s:ST_String" use="required"/> + <xsd:attribute name="pos" type="ST_CaptionPos" use="optional"/> + <xsd:attribute name="chapNum" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="heading" type="ST_DecimalNumber" use="optional"/> + <xsd:attribute name="noLabel" type="s:ST_OnOff" use="optional"/> + <xsd:attribute name="numFmt" type="ST_NumberFormat" use="optional"/> + <xsd:attribute name="sep" type="ST_ChapterSep" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_AutoCaption"> + <xsd:attribute name="name" type="s:ST_String" use="required"/> + <xsd:attribute name="caption" type="s:ST_String" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_AutoCaptions"> + <xsd:sequence> + <xsd:element name="autoCaption" type="CT_AutoCaption" minOccurs="1" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Captions"> + <xsd:sequence> + <xsd:element name="caption" type="CT_Caption" minOccurs="1" maxOccurs="unbounded"/> + <xsd:element name="autoCaptions" type="CT_AutoCaptions" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_DocumentBase"> + <xsd:sequence> + <xsd:element name="background" type="CT_Background" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Document"> + <xsd:complexContent> + <xsd:extension base="CT_DocumentBase"> + <xsd:sequence> + <xsd:element name="body" type="CT_Body" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="conformance" type="s:ST_ConformanceClass"/> + <xsd:attribute ref="mc:Ignorable" use="optional" /> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:complexType name="CT_GlossaryDocument"> + <xsd:complexContent> + <xsd:extension base="CT_DocumentBase"> + <xsd:sequence> + <xsd:element name="docParts" type="CT_DocParts" minOccurs="0"/> + </xsd:sequence> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + <xsd:element name="document" type="CT_Document"/> + <xsd:element name="glossaryDocument" type="CT_GlossaryDocument"/> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd new file mode 100644 index 0000000..0f13678 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd @@ -0,0 +1,116 @@ +<?xml version='1.0'?> +<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" xml:lang="en"> + + <xs:annotation> + <xs:documentation> + See http://www.w3.org/XML/1998/namespace.html and + http://www.w3.org/TR/REC-xml for information about this namespace. + + This schema document describes the XML namespace, in a form + suitable for import by other schema documents. + + Note that local names in this namespace are intended to be defined + only by the World Wide Web Consortium or its subgroups. The + following names are currently defined in this namespace and should + not be used with conflicting semantics by any Working Group, + specification, or document instance: + + base (as an attribute name): denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification. + + lang (as an attribute name): denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification. + + space (as an attribute name): denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification. + + Father (in any context at all): denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: + + In appreciation for his vision, leadership and dedication + the W3C XML Plenary on this 10th day of February, 2000 + reserves for Jon Bosak in perpetuity the XML name + xml:Father + </xs:documentation> + </xs:annotation> + + <xs:annotation> + <xs:documentation>This schema defines attributes and an attribute group + suitable for use by + schemas wishing to allow xml:base, xml:lang or xml:space attributes + on elements they define. + + To enable this, such a schema must import this schema + for the XML namespace, e.g. as follows: + <schema . . .> + . . . + <import namespace="http://www.w3.org/XML/1998/namespace" + schemaLocation="http://www.w3.org/2001/03/xml.xsd"/> + + Subsequently, qualified reference to any of the attributes + or the group defined below will have the desired effect, e.g. + + <type . . .> + . . . + <attributeGroup ref="xml:specialAttrs"/> + + will define a type which will schema-validate an instance + element with any of those attributes</xs:documentation> + </xs:annotation> + + <xs:annotation> + <xs:documentation>In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + http://www.w3.org/2001/03/xml.xsd. + At the date of issue it can also be found at + http://www.w3.org/2001/xml.xsd. + The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML Schema + itself. In other words, if the XML Schema namespace changes, the version + of this document at + http://www.w3.org/2001/xml.xsd will change + accordingly; the version at + http://www.w3.org/2001/03/xml.xsd will not change. + </xs:documentation> + </xs:annotation> + + <xs:attribute name="lang" type="xs:language"> + <xs:annotation> + <xs:documentation>In due course, we should install the relevant ISO 2- and 3-letter + codes as the enumerated possible values . . .</xs:documentation> + </xs:annotation> + </xs:attribute> + + <xs:attribute name="space" default="preserve"> + <xs:simpleType> + <xs:restriction base="xs:NCName"> + <xs:enumeration value="default"/> + <xs:enumeration value="preserve"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + + <xs:attribute name="base" type="xs:anyURI"> + <xs:annotation> + <xs:documentation>See http://www.w3.org/TR/xmlbase/ for + information about this attribute.</xs:documentation> + </xs:annotation> + </xs:attribute> + + <xs:attributeGroup name="specialAttrs"> + <xs:attribute ref="xml:base"/> + <xs:attribute ref="xml:lang"/> + <xs:attribute ref="xml:space"/> + </xs:attributeGroup> + +</xs:schema> diff --git a/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd b/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd new file mode 100644 index 0000000..a6de9d2 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<xs:schema xmlns="http://schemas.openxmlformats.org/package/2006/content-types" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + targetNamespace="http://schemas.openxmlformats.org/package/2006/content-types" + elementFormDefault="qualified" attributeFormDefault="unqualified" blockDefault="#all"> + + <xs:element name="Types" type="CT_Types"/> + <xs:element name="Default" type="CT_Default"/> + <xs:element name="Override" type="CT_Override"/> + + <xs:complexType name="CT_Types"> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element ref="Default"/> + <xs:element ref="Override"/> + </xs:choice> + </xs:complexType> + + <xs:complexType name="CT_Default"> + <xs:attribute name="Extension" type="ST_Extension" use="required"/> + <xs:attribute name="ContentType" type="ST_ContentType" use="required"/> + </xs:complexType> + + <xs:complexType name="CT_Override"> + <xs:attribute name="ContentType" type="ST_ContentType" use="required"/> + <xs:attribute name="PartName" type="xs:anyURI" use="required"/> + </xs:complexType> + + <xs:simpleType name="ST_ContentType"> + <xs:restriction base="xs:string"> + <xs:pattern + value="(((([\p{IsBasicLatin}-[\p{Cc}\(\)<>@,;:\\"/\[\]\?=\{\}\s\t]])+))/((([\p{IsBasicLatin}-[\p{Cc}\(\)<>@,;:\\"/\[\]\?=\{\}\s\t]])+))((\s+)*;(\s+)*(((([\p{IsBasicLatin}-[\p{Cc}\(\)<>@,;:\\"/\[\]\?=\{\}\s\t]])+))=((([\p{IsBasicLatin}-[\p{Cc}\(\)<>@,;:\\"/\[\]\?=\{\}\s\t]])+)|("(([\p{IsLatin-1Supplement}\p{IsBasicLatin}-[\p{Cc}"\n\r]]|(\s+))|(\\[\p{IsBasicLatin}]))*"))))*)" + /> + </xs:restriction> + </xs:simpleType> + + <xs:simpleType name="ST_Extension"> + <xs:restriction base="xs:string"> + <xs:pattern + value="([!$&'\(\)\*\+,:=]|(%[0-9a-fA-F][0-9a-fA-F])|[:@]|[a-zA-Z0-9\-_~])+"/> + </xs:restriction> + </xs:simpleType> +</xs:schema> diff --git a/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd b/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd new file mode 100644 index 0000000..10e978b --- /dev/null +++ b/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xs:schema targetNamespace="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" + xmlns="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" + xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:dcterms="http://purl.org/dc/terms/" elementFormDefault="qualified" blockDefault="#all"> + + <xs:import namespace="http://purl.org/dc/elements/1.1/" + schemaLocation="http://dublincore.org/schemas/xmls/qdc/2003/04/02/dc.xsd"/> + <xs:import namespace="http://purl.org/dc/terms/" + schemaLocation="http://dublincore.org/schemas/xmls/qdc/2003/04/02/dcterms.xsd"/> + <xs:import id="xml" namespace="http://www.w3.org/XML/1998/namespace"/> + + <xs:element name="coreProperties" type="CT_CoreProperties"/> + + <xs:complexType name="CT_CoreProperties"> + <xs:all> + <xs:element name="category" minOccurs="0" maxOccurs="1" type="xs:string"/> + <xs:element name="contentStatus" minOccurs="0" maxOccurs="1" type="xs:string"/> + <xs:element ref="dcterms:created" minOccurs="0" maxOccurs="1"/> + <xs:element ref="dc:creator" minOccurs="0" maxOccurs="1"/> + <xs:element ref="dc:description" minOccurs="0" maxOccurs="1"/> + <xs:element ref="dc:identifier" minOccurs="0" maxOccurs="1"/> + <xs:element name="keywords" minOccurs="0" maxOccurs="1" type="CT_Keywords"/> + <xs:element ref="dc:language" minOccurs="0" maxOccurs="1"/> + <xs:element name="lastModifiedBy" minOccurs="0" maxOccurs="1" type="xs:string"/> + <xs:element name="lastPrinted" minOccurs="0" maxOccurs="1" type="xs:dateTime"/> + <xs:element ref="dcterms:modified" minOccurs="0" maxOccurs="1"/> + <xs:element name="revision" minOccurs="0" maxOccurs="1" type="xs:string"/> + <xs:element ref="dc:subject" minOccurs="0" maxOccurs="1"/> + <xs:element ref="dc:title" minOccurs="0" maxOccurs="1"/> + <xs:element name="version" minOccurs="0" maxOccurs="1" type="xs:string"/> + </xs:all> + </xs:complexType> + + <xs:complexType name="CT_Keywords" mixed="true"> + <xs:sequence> + <xs:element name="value" minOccurs="0" maxOccurs="unbounded" type="CT_Keyword"/> + </xs:sequence> + <xs:attribute ref="xml:lang" use="optional"/> + </xs:complexType> + + <xs:complexType name="CT_Keyword"> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute ref="xml:lang" use="optional"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + +</xs:schema> diff --git a/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd b/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd new file mode 100644 index 0000000..4248bf7 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsd:schema xmlns="http://schemas.openxmlformats.org/package/2006/digital-signature" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + targetNamespace="http://schemas.openxmlformats.org/package/2006/digital-signature" + elementFormDefault="qualified" attributeFormDefault="unqualified" blockDefault="#all"> + + <xsd:element name="SignatureTime" type="CT_SignatureTime"/> + <xsd:element name="RelationshipReference" type="CT_RelationshipReference"/> + <xsd:element name="RelationshipsGroupReference" type="CT_RelationshipsGroupReference"/> + + <xsd:complexType name="CT_SignatureTime"> + <xsd:sequence> + <xsd:element name="Format" type="ST_Format"/> + <xsd:element name="Value" type="ST_Value"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="CT_RelationshipReference"> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="SourceId" type="xsd:string" use="required"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + + <xsd:complexType name="CT_RelationshipsGroupReference"> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="SourceType" type="xsd:anyURI" use="required"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + + <xsd:simpleType name="ST_Format"> + <xsd:restriction base="xsd:string"> + <xsd:pattern + value="(YYYY)|(YYYY-MM)|(YYYY-MM-DD)|(YYYY-MM-DDThh:mmTZD)|(YYYY-MM-DDThh:mm:ssTZD)|(YYYY-MM-DDThh:mm:ss.sTZD)" + /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="ST_Value"> + <xsd:restriction base="xsd:string"> + <xsd:pattern + value="(([0-9][0-9][0-9][0-9]))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2))))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2)))-((0[1-9])|(1[0-9])|(2[0-9])|(3(0|1))))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2)))-((0[1-9])|(1[0-9])|(2[0-9])|(3(0|1)))T((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9]))(((\+|-)((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])))|Z))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2)))-((0[1-9])|(1[0-9])|(2[0-9])|(3(0|1)))T((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9]))(((\+|-)((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])))|Z))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2)))-((0[1-9])|(1[0-9])|(2[0-9])|(3(0|1)))T((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])):(((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9]))\.[0-9])(((\+|-)((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])))|Z))" + /> + </xsd:restriction> + </xsd:simpleType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd b/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd new file mode 100644 index 0000000..5649746 --- /dev/null +++ b/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<xsd:schema xmlns="http://schemas.openxmlformats.org/package/2006/relationships" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + targetNamespace="http://schemas.openxmlformats.org/package/2006/relationships" + elementFormDefault="qualified" attributeFormDefault="unqualified" blockDefault="#all"> + + <xsd:element name="Relationships" type="CT_Relationships"/> + <xsd:element name="Relationship" type="CT_Relationship"/> + + <xsd:complexType name="CT_Relationships"> + <xsd:sequence> + <xsd:element ref="Relationship" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="CT_Relationship"> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="TargetMode" type="ST_TargetMode" use="optional"/> + <xsd:attribute name="Target" type="xsd:anyURI" use="required"/> + <xsd:attribute name="Type" type="xsd:anyURI" use="required"/> + <xsd:attribute name="Id" type="xsd:ID" use="required"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + + <xsd:simpleType name="ST_TargetMode"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="External"/> + <xsd:enumeration value="Internal"/> + </xsd:restriction> + </xsd:simpleType> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/mce/mc.xsd b/skills/pptx/ooxml/schemas/mce/mc.xsd new file mode 100644 index 0000000..ef72545 --- /dev/null +++ b/skills/pptx/ooxml/schemas/mce/mc.xsd @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="utf-8"?> +<xsd:schema xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + attributeFormDefault="unqualified" elementFormDefault="qualified" + targetNamespace="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + + <!-- + This XSD is a modified version of the one found at: + https://github.com/plutext/docx4j/blob/master/xsd/mce/markup-compatibility-2006-MINIMAL.xsd + + This XSD has 2 objectives: + + 1. round tripping @mc:Ignorable + + <w:document + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" + mc:Ignorable="w14 w15 wp14"> + + 2. enabling AlternateContent to be manipulated in certain elements + (in the unusual case where the content model is xsd:any, it doesn't have to be explicitly added) + + See further ECMA-376, 4th Edition, Office Open XML File Formats + Part 3 : Markup Compatibility and Extensibility + --> + + <!-- Objective 1 --> + <xsd:attribute name="Ignorable" type="xsd:string" /> + + <!-- Objective 2 --> + <xsd:attribute name="MustUnderstand" type="xsd:string" /> + <xsd:attribute name="ProcessContent" type="xsd:string" /> + +<!-- An AlternateContent element shall contain one or more Choice child elements, optionally followed by a +Fallback child element. If present, there shall be only one Fallback element, and it shall follow all Choice +elements. --> + <xsd:element name="AlternateContent"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="Choice" minOccurs="0" maxOccurs="unbounded"> + <xsd:complexType> + <xsd:sequence> + <xsd:any minOccurs="0" maxOccurs="unbounded" + processContents="strict"> + </xsd:any> + </xsd:sequence> + <xsd:attribute name="Requires" type="xsd:string" use="required" /> + <xsd:attribute ref="mc:Ignorable" use="optional" /> + <xsd:attribute ref="mc:MustUnderstand" use="optional" /> + <xsd:attribute ref="mc:ProcessContent" use="optional" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="Fallback" minOccurs="0" maxOccurs="1"> + <xsd:complexType> + <xsd:sequence> + <xsd:any minOccurs="0" maxOccurs="unbounded" + processContents="strict"> + </xsd:any> + </xsd:sequence> + <xsd:attribute ref="mc:Ignorable" use="optional" /> + <xsd:attribute ref="mc:MustUnderstand" use="optional" /> + <xsd:attribute ref="mc:ProcessContent" use="optional" /> + </xsd:complexType> + </xsd:element> + </xsd:sequence> + <!-- AlternateContent elements might include the attributes Ignorable, + MustUnderstand and ProcessContent described in this Part of ECMA-376. These + attributes’ qualified names shall be prefixed when associated with an AlternateContent + element. --> + <xsd:attribute ref="mc:Ignorable" use="optional" /> + <xsd:attribute ref="mc:MustUnderstand" use="optional" /> + <xsd:attribute ref="mc:ProcessContent" use="optional" /> + </xsd:complexType> + </xsd:element> +</xsd:schema> diff --git a/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd b/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd new file mode 100644 index 0000000..f65f777 --- /dev/null +++ b/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd @@ -0,0 +1,560 @@ + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns="http://schemas.microsoft.com/office/word/2010/wordml" targetNamespace="http://schemas.microsoft.com/office/word/2010/wordml"> + <!-- <xsd:import id="rel" namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships" schemaLocation="orel.xsd"/> --> + <xsd:import id="w" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/> + <!-- <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main" schemaLocation="oartbasetypes.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main" schemaLocation="oartsplineproperties.xsd"/> --> + <xsd:complexType name="CT_LongHexNumber"> + <xsd:attribute name="val" type="w:ST_LongHexNumber" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_OnOff"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="true"/> + <xsd:enumeration value="false"/> + <xsd:enumeration value="0"/> + <xsd:enumeration value="1"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_OnOff"> + <xsd:attribute name="val" type="ST_OnOff"/> + </xsd:complexType> + <xsd:element name="docId" type="CT_LongHexNumber"/> + <xsd:element name="conflictMode" type="CT_OnOff"/> + <xsd:attributeGroup name="AG_Parids"> + <xsd:attribute name="paraId" type="w:ST_LongHexNumber"/> + <xsd:attribute name="textId" type="w:ST_LongHexNumber"/> + </xsd:attributeGroup> + <xsd:attribute name="anchorId" type="w:ST_LongHexNumber"/> + <xsd:attribute name="noSpellErr" type="ST_OnOff"/> + <xsd:element name="customXmlConflictInsRangeStart" type="w:CT_TrackChange"/> + <xsd:element name="customXmlConflictInsRangeEnd" type="w:CT_Markup"/> + <xsd:element name="customXmlConflictDelRangeStart" type="w:CT_TrackChange"/> + <xsd:element name="customXmlConflictDelRangeEnd" type="w:CT_Markup"/> + <xsd:group name="EG_RunLevelConflicts"> + <xsd:sequence> + <xsd:element name="conflictIns" type="w:CT_RunTrackChange" minOccurs="0"/> + <xsd:element name="conflictDel" type="w:CT_RunTrackChange" minOccurs="0"/> + </xsd:sequence> + </xsd:group> + <xsd:group name="EG_Conflicts"> + <xsd:choice> + <xsd:element name="conflictIns" type="w:CT_TrackChange" minOccurs="0"/> + <xsd:element name="conflictDel" type="w:CT_TrackChange" minOccurs="0"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_Percentage"> + <xsd:attribute name="val" type="a:ST_Percentage" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_PositiveFixedPercentage"> + <xsd:attribute name="val" type="a:ST_PositiveFixedPercentage" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_PositivePercentage"> + <xsd:attribute name="val" type="a:ST_PositivePercentage" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_SchemeColorVal"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="bg1"/> + <xsd:enumeration value="tx1"/> + <xsd:enumeration value="bg2"/> + <xsd:enumeration value="tx2"/> + <xsd:enumeration value="accent1"/> + <xsd:enumeration value="accent2"/> + <xsd:enumeration value="accent3"/> + <xsd:enumeration value="accent4"/> + <xsd:enumeration value="accent5"/> + <xsd:enumeration value="accent6"/> + <xsd:enumeration value="hlink"/> + <xsd:enumeration value="folHlink"/> + <xsd:enumeration value="dk1"/> + <xsd:enumeration value="lt1"/> + <xsd:enumeration value="dk2"/> + <xsd:enumeration value="lt2"/> + <xsd:enumeration value="phClr"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_RectAlignment"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="tl"/> + <xsd:enumeration value="t"/> + <xsd:enumeration value="tr"/> + <xsd:enumeration value="l"/> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="r"/> + <xsd:enumeration value="bl"/> + <xsd:enumeration value="b"/> + <xsd:enumeration value="br"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PathShadeType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="shape"/> + <xsd:enumeration value="circle"/> + <xsd:enumeration value="rect"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_LineCap"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="rnd"/> + <xsd:enumeration value="sq"/> + <xsd:enumeration value="flat"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PresetLineDashVal"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="solid"/> + <xsd:enumeration value="dot"/> + <xsd:enumeration value="sysDot"/> + <xsd:enumeration value="dash"/> + <xsd:enumeration value="sysDash"/> + <xsd:enumeration value="lgDash"/> + <xsd:enumeration value="dashDot"/> + <xsd:enumeration value="sysDashDot"/> + <xsd:enumeration value="lgDashDot"/> + <xsd:enumeration value="lgDashDotDot"/> + <xsd:enumeration value="sysDashDotDot"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_PenAlignment"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="ctr"/> + <xsd:enumeration value="in"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_CompoundLine"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="sng"/> + <xsd:enumeration value="dbl"/> + <xsd:enumeration value="thickThin"/> + <xsd:enumeration value="thinThick"/> + <xsd:enumeration value="tri"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_RelativeRect"> + <xsd:attribute name="l" use="optional" type="a:ST_Percentage"/> + <xsd:attribute name="t" use="optional" type="a:ST_Percentage"/> + <xsd:attribute name="r" use="optional" type="a:ST_Percentage"/> + <xsd:attribute name="b" use="optional" type="a:ST_Percentage"/> + </xsd:complexType> + <xsd:group name="EG_ColorTransform"> + <xsd:choice> + <xsd:element name="tint" type="CT_PositiveFixedPercentage"/> + <xsd:element name="shade" type="CT_PositiveFixedPercentage"/> + <xsd:element name="alpha" type="CT_PositiveFixedPercentage"/> + <xsd:element name="hueMod" type="CT_PositivePercentage"/> + <xsd:element name="sat" type="CT_Percentage"/> + <xsd:element name="satOff" type="CT_Percentage"/> + <xsd:element name="satMod" type="CT_Percentage"/> + <xsd:element name="lum" type="CT_Percentage"/> + <xsd:element name="lumOff" type="CT_Percentage"/> + <xsd:element name="lumMod" type="CT_Percentage"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_SRgbColor"> + <xsd:sequence> + <xsd:group ref="EG_ColorTransform" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="val" type="s:ST_HexColorRGB" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_SchemeColor"> + <xsd:sequence> + <xsd:group ref="EG_ColorTransform" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="val" type="ST_SchemeColorVal" use="required"/> + </xsd:complexType> + <xsd:group name="EG_ColorChoice"> + <xsd:choice> + <xsd:element name="srgbClr" type="CT_SRgbColor"/> + <xsd:element name="schemeClr" type="CT_SchemeColor"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_Color"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GradientStop"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice"/> + </xsd:sequence> + <xsd:attribute name="pos" type="a:ST_PositiveFixedPercentage" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_GradientStopList"> + <xsd:sequence> + <xsd:element name="gs" type="CT_GradientStop" minOccurs="2" maxOccurs="10"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_LinearShadeProperties"> + <xsd:attribute name="ang" type="a:ST_PositiveFixedAngle" use="optional"/> + <xsd:attribute name="scaled" type="ST_OnOff" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_PathShadeProperties"> + <xsd:sequence> + <xsd:element name="fillToRect" type="CT_RelativeRect" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="path" type="ST_PathShadeType" use="optional"/> + </xsd:complexType> + <xsd:group name="EG_ShadeProperties"> + <xsd:choice> + <xsd:element name="lin" type="CT_LinearShadeProperties"/> + <xsd:element name="path" type="CT_PathShadeProperties"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_SolidColorFillProperties"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_GradientFillProperties"> + <xsd:sequence> + <xsd:element name="gsLst" type="CT_GradientStopList" minOccurs="0"/> + <xsd:group ref="EG_ShadeProperties" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_FillProperties"> + <xsd:choice> + <xsd:element name="noFill" type="w:CT_Empty"/> + <xsd:element name="solidFill" type="CT_SolidColorFillProperties"/> + <xsd:element name="gradFill" type="CT_GradientFillProperties"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_PresetLineDashProperties"> + <xsd:attribute name="val" type="ST_PresetLineDashVal" use="optional"/> + </xsd:complexType> + <xsd:group name="EG_LineDashProperties"> + <xsd:choice> + <xsd:element name="prstDash" type="CT_PresetLineDashProperties"/> + </xsd:choice> + </xsd:group> + <xsd:complexType name="CT_LineJoinMiterProperties"> + <xsd:attribute name="lim" type="a:ST_PositivePercentage" use="optional"/> + </xsd:complexType> + <xsd:group name="EG_LineJoinProperties"> + <xsd:choice> + <xsd:element name="round" type="w:CT_Empty"/> + <xsd:element name="bevel" type="w:CT_Empty"/> + <xsd:element name="miter" type="CT_LineJoinMiterProperties"/> + </xsd:choice> + </xsd:group> + <xsd:simpleType name="ST_PresetCameraType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="legacyObliqueTopLeft"/> + <xsd:enumeration value="legacyObliqueTop"/> + <xsd:enumeration value="legacyObliqueTopRight"/> + <xsd:enumeration value="legacyObliqueLeft"/> + <xsd:enumeration value="legacyObliqueFront"/> + <xsd:enumeration value="legacyObliqueRight"/> + <xsd:enumeration value="legacyObliqueBottomLeft"/> + <xsd:enumeration value="legacyObliqueBottom"/> + <xsd:enumeration value="legacyObliqueBottomRight"/> + <xsd:enumeration value="legacyPerspectiveTopLeft"/> + <xsd:enumeration value="legacyPerspectiveTop"/> + <xsd:enumeration value="legacyPerspectiveTopRight"/> + <xsd:enumeration value="legacyPerspectiveLeft"/> + <xsd:enumeration value="legacyPerspectiveFront"/> + <xsd:enumeration value="legacyPerspectiveRight"/> + <xsd:enumeration value="legacyPerspectiveBottomLeft"/> + <xsd:enumeration value="legacyPerspectiveBottom"/> + <xsd:enumeration value="legacyPerspectiveBottomRight"/> + <xsd:enumeration value="orthographicFront"/> + <xsd:enumeration value="isometricTopUp"/> + <xsd:enumeration value="isometricTopDown"/> + <xsd:enumeration value="isometricBottomUp"/> + <xsd:enumeration value="isometricBottomDown"/> + <xsd:enumeration value="isometricLeftUp"/> + <xsd:enumeration value="isometricLeftDown"/> + <xsd:enumeration value="isometricRightUp"/> + <xsd:enumeration value="isometricRightDown"/> + <xsd:enumeration value="isometricOffAxis1Left"/> + <xsd:enumeration value="isometricOffAxis1Right"/> + <xsd:enumeration value="isometricOffAxis1Top"/> + <xsd:enumeration value="isometricOffAxis2Left"/> + <xsd:enumeration value="isometricOffAxis2Right"/> + <xsd:enumeration value="isometricOffAxis2Top"/> + <xsd:enumeration value="isometricOffAxis3Left"/> + <xsd:enumeration value="isometricOffAxis3Right"/> + <xsd:enumeration value="isometricOffAxis3Bottom"/> + <xsd:enumeration value="isometricOffAxis4Left"/> + <xsd:enumeration value="isometricOffAxis4Right"/> + <xsd:enumeration value="isometricOffAxis4Bottom"/> + <xsd:enumeration value="obliqueTopLeft"/> + <xsd:enumeration value="obliqueTop"/> + <xsd:enumeration value="obliqueTopRight"/> + <xsd:enumeration value="obliqueLeft"/> + <xsd:enumeration value="obliqueRight"/> + <xsd:enumeration value="obliqueBottomLeft"/> + <xsd:enumeration value="obliqueBottom"/> + <xsd:enumeration value="obliqueBottomRight"/> + <xsd:enumeration value="perspectiveFront"/> + <xsd:enumeration value="perspectiveLeft"/> + <xsd:enumeration value="perspectiveRight"/> + <xsd:enumeration value="perspectiveAbove"/> + <xsd:enumeration value="perspectiveBelow"/> + <xsd:enumeration value="perspectiveAboveLeftFacing"/> + <xsd:enumeration value="perspectiveAboveRightFacing"/> + <xsd:enumeration value="perspectiveContrastingLeftFacing"/> + <xsd:enumeration value="perspectiveContrastingRightFacing"/> + <xsd:enumeration value="perspectiveHeroicLeftFacing"/> + <xsd:enumeration value="perspectiveHeroicRightFacing"/> + <xsd:enumeration value="perspectiveHeroicExtremeLeftFacing"/> + <xsd:enumeration value="perspectiveHeroicExtremeRightFacing"/> + <xsd:enumeration value="perspectiveRelaxed"/> + <xsd:enumeration value="perspectiveRelaxedModerately"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Camera"> + <xsd:attribute name="prst" use="required" type="ST_PresetCameraType"/> + </xsd:complexType> + <xsd:complexType name="CT_SphereCoords"> + <xsd:attribute name="lat" type="a:ST_PositiveFixedAngle" use="required"/> + <xsd:attribute name="lon" type="a:ST_PositiveFixedAngle" use="required"/> + <xsd:attribute name="rev" type="a:ST_PositiveFixedAngle" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_LightRigType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="legacyFlat1"/> + <xsd:enumeration value="legacyFlat2"/> + <xsd:enumeration value="legacyFlat3"/> + <xsd:enumeration value="legacyFlat4"/> + <xsd:enumeration value="legacyNormal1"/> + <xsd:enumeration value="legacyNormal2"/> + <xsd:enumeration value="legacyNormal3"/> + <xsd:enumeration value="legacyNormal4"/> + <xsd:enumeration value="legacyHarsh1"/> + <xsd:enumeration value="legacyHarsh2"/> + <xsd:enumeration value="legacyHarsh3"/> + <xsd:enumeration value="legacyHarsh4"/> + <xsd:enumeration value="threePt"/> + <xsd:enumeration value="balanced"/> + <xsd:enumeration value="soft"/> + <xsd:enumeration value="harsh"/> + <xsd:enumeration value="flood"/> + <xsd:enumeration value="contrasting"/> + <xsd:enumeration value="morning"/> + <xsd:enumeration value="sunrise"/> + <xsd:enumeration value="sunset"/> + <xsd:enumeration value="chilly"/> + <xsd:enumeration value="freezing"/> + <xsd:enumeration value="flat"/> + <xsd:enumeration value="twoPt"/> + <xsd:enumeration value="glow"/> + <xsd:enumeration value="brightRoom"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="ST_LightRigDirection"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="tl"/> + <xsd:enumeration value="t"/> + <xsd:enumeration value="tr"/> + <xsd:enumeration value="l"/> + <xsd:enumeration value="r"/> + <xsd:enumeration value="bl"/> + <xsd:enumeration value="b"/> + <xsd:enumeration value="br"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_LightRig"> + <xsd:sequence> + <xsd:element name="rot" type="CT_SphereCoords" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="rig" type="ST_LightRigType" use="required"/> + <xsd:attribute name="dir" type="ST_LightRigDirection" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_BevelPresetType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="relaxedInset"/> + <xsd:enumeration value="circle"/> + <xsd:enumeration value="slope"/> + <xsd:enumeration value="cross"/> + <xsd:enumeration value="angle"/> + <xsd:enumeration value="softRound"/> + <xsd:enumeration value="convex"/> + <xsd:enumeration value="coolSlant"/> + <xsd:enumeration value="divot"/> + <xsd:enumeration value="riblet"/> + <xsd:enumeration value="hardEdge"/> + <xsd:enumeration value="artDeco"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Bevel"> + <xsd:attribute name="w" type="a:ST_PositiveCoordinate" use="optional"/> + <xsd:attribute name="h" type="a:ST_PositiveCoordinate" use="optional"/> + <xsd:attribute name="prst" type="ST_BevelPresetType" use="optional"/> + </xsd:complexType> + <xsd:simpleType name="ST_PresetMaterialType"> + <xsd:restriction base="xsd:token"> + <xsd:enumeration value="legacyMatte"/> + <xsd:enumeration value="legacyPlastic"/> + <xsd:enumeration value="legacyMetal"/> + <xsd:enumeration value="legacyWireframe"/> + <xsd:enumeration value="matte"/> + <xsd:enumeration value="plastic"/> + <xsd:enumeration value="metal"/> + <xsd:enumeration value="warmMatte"/> + <xsd:enumeration value="translucentPowder"/> + <xsd:enumeration value="powder"/> + <xsd:enumeration value="dkEdge"/> + <xsd:enumeration value="softEdge"/> + <xsd:enumeration value="clear"/> + <xsd:enumeration value="flat"/> + <xsd:enumeration value="softmetal"/> + <xsd:enumeration value="none"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Glow"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice"/> + </xsd:sequence> + <xsd:attribute name="rad" use="optional" type="a:ST_PositiveCoordinate"/> + </xsd:complexType> + <xsd:complexType name="CT_Shadow"> + <xsd:sequence> + <xsd:group ref="EG_ColorChoice"/> + </xsd:sequence> + <xsd:attribute name="blurRad" use="optional" type="a:ST_PositiveCoordinate"/> + <xsd:attribute name="dist" use="optional" type="a:ST_PositiveCoordinate"/> + <xsd:attribute name="dir" use="optional" type="a:ST_PositiveFixedAngle"/> + <xsd:attribute name="sx" use="optional" type="a:ST_Percentage"/> + <xsd:attribute name="sy" use="optional" type="a:ST_Percentage"/> + <xsd:attribute name="kx" use="optional" type="a:ST_FixedAngle"/> + <xsd:attribute name="ky" use="optional" type="a:ST_FixedAngle"/> + <xsd:attribute name="algn" use="optional" type="ST_RectAlignment"/> + </xsd:complexType> + <xsd:complexType name="CT_Reflection"> + <xsd:attribute name="blurRad" use="optional" type="a:ST_PositiveCoordinate"/> + <xsd:attribute name="stA" use="optional" type="a:ST_PositiveFixedPercentage"/> + <xsd:attribute name="stPos" use="optional" type="a:ST_PositiveFixedPercentage"/> + <xsd:attribute name="endA" use="optional" type="a:ST_PositiveFixedPercentage"/> + <xsd:attribute name="endPos" use="optional" type="a:ST_PositiveFixedPercentage"/> + <xsd:attribute name="dist" use="optional" type="a:ST_PositiveCoordinate"/> + <xsd:attribute name="dir" use="optional" type="a:ST_PositiveFixedAngle"/> + <xsd:attribute name="fadeDir" use="optional" type="a:ST_PositiveFixedAngle"/> + <xsd:attribute name="sx" use="optional" type="a:ST_Percentage"/> + <xsd:attribute name="sy" use="optional" type="a:ST_Percentage"/> + <xsd:attribute name="kx" use="optional" type="a:ST_FixedAngle"/> + <xsd:attribute name="ky" use="optional" type="a:ST_FixedAngle"/> + <xsd:attribute name="algn" use="optional" type="ST_RectAlignment"/> + </xsd:complexType> + <xsd:complexType name="CT_FillTextEffect"> + <xsd:sequence> + <xsd:group ref="EG_FillProperties" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_TextOutlineEffect"> + <xsd:sequence> + <xsd:group ref="EG_FillProperties" minOccurs="0"/> + <xsd:group ref="EG_LineDashProperties" minOccurs="0"/> + <xsd:group ref="EG_LineJoinProperties" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="w" use="optional" type="a:ST_LineWidth"/> + <xsd:attribute name="cap" use="optional" type="ST_LineCap"/> + <xsd:attribute name="cmpd" use="optional" type="ST_CompoundLine"/> + <xsd:attribute name="algn" use="optional" type="ST_PenAlignment"/> + </xsd:complexType> + <xsd:complexType name="CT_Scene3D"> + <xsd:sequence> + <xsd:element name="camera" type="CT_Camera"/> + <xsd:element name="lightRig" type="CT_LightRig"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_Props3D"> + <xsd:sequence> + <xsd:element name="bevelT" type="CT_Bevel" minOccurs="0"/> + <xsd:element name="bevelB" type="CT_Bevel" minOccurs="0"/> + <xsd:element name="extrusionClr" type="CT_Color" minOccurs="0"/> + <xsd:element name="contourClr" type="CT_Color" minOccurs="0"/> + </xsd:sequence> + <xsd:attribute name="extrusionH" type="a:ST_PositiveCoordinate" use="optional"/> + <xsd:attribute name="contourW" type="a:ST_PositiveCoordinate" use="optional"/> + <xsd:attribute name="prstMaterial" type="ST_PresetMaterialType" use="optional"/> + </xsd:complexType> + <xsd:group name="EG_RPrTextEffects"> + <xsd:sequence> + <xsd:element name="glow" minOccurs="0" type="CT_Glow"/> + <xsd:element name="shadow" minOccurs="0" type="CT_Shadow"/> + <xsd:element name="reflection" minOccurs="0" type="CT_Reflection"/> + <xsd:element name="textOutline" minOccurs="0" type="CT_TextOutlineEffect"/> + <xsd:element name="textFill" minOccurs="0" type="CT_FillTextEffect"/> + <xsd:element name="scene3d" minOccurs="0" type="CT_Scene3D"/> + <xsd:element name="props3d" minOccurs="0" type="CT_Props3D"/> + </xsd:sequence> + </xsd:group> + <xsd:simpleType name="ST_Ligatures"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="none"/> + <xsd:enumeration value="standard"/> + <xsd:enumeration value="contextual"/> + <xsd:enumeration value="historical"/> + <xsd:enumeration value="discretional"/> + <xsd:enumeration value="standardContextual"/> + <xsd:enumeration value="standardHistorical"/> + <xsd:enumeration value="contextualHistorical"/> + <xsd:enumeration value="standardDiscretional"/> + <xsd:enumeration value="contextualDiscretional"/> + <xsd:enumeration value="historicalDiscretional"/> + <xsd:enumeration value="standardContextualHistorical"/> + <xsd:enumeration value="standardContextualDiscretional"/> + <xsd:enumeration value="standardHistoricalDiscretional"/> + <xsd:enumeration value="contextualHistoricalDiscretional"/> + <xsd:enumeration value="all"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Ligatures"> + <xsd:attribute name="val" type="ST_Ligatures" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_NumForm"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="default"/> + <xsd:enumeration value="lining"/> + <xsd:enumeration value="oldStyle"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_NumForm"> + <xsd:attribute name="val" type="ST_NumForm" use="required"/> + </xsd:complexType> + <xsd:simpleType name="ST_NumSpacing"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="default"/> + <xsd:enumeration value="proportional"/> + <xsd:enumeration value="tabular"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_NumSpacing"> + <xsd:attribute name="val" type="ST_NumSpacing" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_StyleSet"> + <xsd:attribute name="id" type="s:ST_UnsignedDecimalNumber" use="required"/> + <xsd:attribute name="val" type="ST_OnOff" use="optional"/> + </xsd:complexType> + <xsd:complexType name="CT_StylisticSets"> + <xsd:sequence minOccurs="0"> + <xsd:element name="styleSet" minOccurs="0" maxOccurs="unbounded" type="CT_StyleSet"/> + </xsd:sequence> + </xsd:complexType> + <xsd:group name="EG_RPrOpenType"> + <xsd:sequence> + <xsd:element name="ligatures" minOccurs="0" type="CT_Ligatures"/> + <xsd:element name="numForm" minOccurs="0" type="CT_NumForm"/> + <xsd:element name="numSpacing" minOccurs="0" type="CT_NumSpacing"/> + <xsd:element name="stylisticSets" minOccurs="0" type="CT_StylisticSets"/> + <xsd:element name="cntxtAlts" minOccurs="0" type="CT_OnOff"/> + </xsd:sequence> + </xsd:group> + <xsd:element name="discardImageEditingData" type="CT_OnOff"/> + <xsd:element name="defaultImageDpi" type="CT_DefaultImageDpi"/> + <xsd:complexType name="CT_DefaultImageDpi"> + <xsd:attribute name="val" type="w:ST_DecimalNumber" use="required"/> + </xsd:complexType> + <xsd:element name="entityPicker" type="w:CT_Empty"/> + <xsd:complexType name="CT_SdtCheckboxSymbol"> + <xsd:attribute name="font" type="s:ST_String"/> + <xsd:attribute name="val" type="w:ST_ShortHexNumber"/> + </xsd:complexType> + <xsd:complexType name="CT_SdtCheckbox"> + <xsd:sequence> + <xsd:element name="checked" type="CT_OnOff" minOccurs="0"/> + <xsd:element name="checkedState" type="CT_SdtCheckboxSymbol" minOccurs="0"/> + <xsd:element name="uncheckedState" type="CT_SdtCheckboxSymbol" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="checkbox" type="CT_SdtCheckbox"/> + </xsd:schema> diff --git a/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd b/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd new file mode 100644 index 0000000..6b00755 --- /dev/null +++ b/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd @@ -0,0 +1,67 @@ + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2012/wordml" targetNamespace="http://schemas.microsoft.com/office/word/2012/wordml"> + <xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/> + <xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" schemaLocation="../ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd"/> + <xsd:element name="color" type="w12:CT_Color"/> + <xsd:simpleType name="ST_SdtAppearance"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="boundingBox"/> + <xsd:enumeration value="tags"/> + <xsd:enumeration value="hidden"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:element name="dataBinding" type="w12:CT_DataBinding"/> + <xsd:complexType name="CT_SdtAppearance"> + <xsd:attribute name="val" type="ST_SdtAppearance"/> + </xsd:complexType> + <xsd:element name="appearance" type="CT_SdtAppearance"/> + <xsd:complexType name="CT_CommentsEx"> + <xsd:sequence> + <xsd:element name="commentEx" type="CT_CommentEx" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CommentEx"> + <xsd:attribute name="paraId" type="w12:ST_LongHexNumber" use="required"/> + <xsd:attribute name="paraIdParent" type="w12:ST_LongHexNumber" use="optional"/> + <xsd:attribute name="done" type="s:ST_OnOff" use="optional"/> + </xsd:complexType> + <xsd:element name="commentsEx" type="CT_CommentsEx"/> + <xsd:complexType name="CT_People"> + <xsd:sequence> + <xsd:element name="person" type="CT_Person" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_PresenceInfo"> + <xsd:attribute name="providerId" type="xsd:string" use="required"/> + <xsd:attribute name="userId" type="xsd:string" use="required"/> + </xsd:complexType> + <xsd:complexType name="CT_Person"> + <xsd:sequence> + <xsd:element name="presenceInfo" type="CT_PresenceInfo" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="author" type="s:ST_String" use="required"/> + </xsd:complexType> + <xsd:element name="people" type="CT_People"/> + <xsd:complexType name="CT_SdtRepeatedSection"> + <xsd:sequence> + <xsd:element name="sectionTitle" type="w12:CT_String" minOccurs="0"/> + <xsd:element name="doNotAllowInsertDeleteSection" type="w12:CT_OnOff" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:simpleType name="ST_Guid"> + <xsd:restriction base="xsd:token"> + <xsd:pattern value="\{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\}"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:complexType name="CT_Guid"> + <xsd:attribute name="val" type="ST_Guid"/> + </xsd:complexType> + <xsd:element name="repeatingSection" type="CT_SdtRepeatedSection"/> + <xsd:element name="repeatingSectionItem" type="w12:CT_Empty"/> + <xsd:element name="chartTrackingRefBased" type="w12:CT_OnOff"/> + <xsd:element name="collapsed" type="w12:CT_OnOff"/> + <xsd:element name="docId" type="CT_Guid"/> + <xsd:element name="footnoteColumns" type="w12:CT_DecimalNumber"/> + <xsd:element name="webExtensionLinked" type="w12:CT_OnOff"/> + <xsd:element name="webExtensionCreated" type="w12:CT_OnOff"/> + <xsd:attribute name="restartNumberingAfterBreak" type="s:ST_OnOff"/> + </xsd:schema> diff --git a/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd b/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd new file mode 100644 index 0000000..f321d33 --- /dev/null +++ b/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd @@ -0,0 +1,14 @@ + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2018/wordml" targetNamespace="http://schemas.microsoft.com/office/word/2018/wordml"> + <xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/> + <xsd:complexType name="CT_Extension"> + <xsd:sequence> + <xsd:any processContents="lax"/> + </xsd:sequence> + <xsd:attribute name="uri" type="xsd:token"/> + </xsd:complexType> + <xsd:complexType name="CT_ExtensionList"> + <xsd:sequence> + <xsd:element name="ext" type="CT_Extension" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + </xsd:schema> diff --git a/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd b/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd new file mode 100644 index 0000000..364c6a9 --- /dev/null +++ b/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd @@ -0,0 +1,20 @@ + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2018/wordml/cex" targetNamespace="http://schemas.microsoft.com/office/word/2018/wordml/cex"> + <xsd:import id="w16" namespace="http://schemas.microsoft.com/office/word/2018/wordml" schemaLocation="wml-2018.xsd"/> + <xsd:import id="w" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/> + <xsd:import id="s" namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" schemaLocation="../ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd"/> + <xsd:complexType name="CT_CommentsExtensible"> + <xsd:sequence> + <xsd:element name="commentExtensible" type="CT_CommentExtensible" minOccurs="0" maxOccurs="unbounded"/> + <xsd:element name="extLst" type="w16:CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CommentExtensible"> + <xsd:sequence> + <xsd:element name="extLst" type="w16:CT_ExtensionList" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + <xsd:attribute name="durableId" type="w:ST_LongHexNumber" use="required"/> + <xsd:attribute name="dateUtc" type="w:ST_DateTime" use="optional"/> + <xsd:attribute name="intelligentPlaceholder" type="s:ST_OnOff" use="optional"/> + </xsd:complexType> + <xsd:element name="commentsExtensible" type="CT_CommentsExtensible"/> + </xsd:schema> diff --git a/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd b/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd new file mode 100644 index 0000000..fed9d15 --- /dev/null +++ b/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd @@ -0,0 +1,13 @@ + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2016/wordml/cid" targetNamespace="http://schemas.microsoft.com/office/word/2016/wordml/cid"> + <xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/> + <xsd:complexType name="CT_CommentsIds"> + <xsd:sequence> + <xsd:element name="commentId" type="CT_CommentId" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="CT_CommentId"> + <xsd:attribute name="paraId" type="w12:ST_LongHexNumber" use="required"/> + <xsd:attribute name="durableId" type="w12:ST_LongHexNumber" use="required"/> + </xsd:complexType> + <xsd:element name="commentsIds" type="CT_CommentsIds"/> + </xsd:schema> diff --git a/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd b/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd new file mode 100644 index 0000000..680cf15 --- /dev/null +++ b/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd @@ -0,0 +1,4 @@ + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" targetNamespace="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash"> + <xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/> + <xsd:attribute name="storeItemChecksum" type="w12:ST_String"/> + </xsd:schema> diff --git a/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd b/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd new file mode 100644 index 0000000..89ada90 --- /dev/null +++ b/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd @@ -0,0 +1,8 @@ + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2015/wordml/symex" targetNamespace="http://schemas.microsoft.com/office/word/2015/wordml/symex"> + <xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/> + <xsd:complexType name="CT_SymEx"> + <xsd:attribute name="font" type="w12:ST_String"/> + <xsd:attribute name="char" type="w12:ST_LongHexNumber"/> + </xsd:complexType> + <xsd:element name="symEx" type="CT_SymEx"/> + </xsd:schema> diff --git a/skills/pptx/ooxml/scripts/pack.py b/skills/pptx/ooxml/scripts/pack.py new file mode 100755 index 0000000..68bc088 --- /dev/null +++ b/skills/pptx/ooxml/scripts/pack.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +""" +Tool to pack a directory into a .docx, .pptx, or .xlsx file with XML formatting undone. + +Example usage: + python pack.py <input_directory> <office_file> [--force] +""" + +import argparse +import shutil +import subprocess +import sys +import tempfile +import defusedxml.minidom +import zipfile +from pathlib import Path + + +def main(): + parser = argparse.ArgumentParser(description="Pack a directory into an Office file") + parser.add_argument("input_directory", help="Unpacked Office document directory") + parser.add_argument("output_file", help="Output Office file (.docx/.pptx/.xlsx)") + parser.add_argument("--force", action="store_true", help="Skip validation") + args = parser.parse_args() + + try: + success = pack_document( + args.input_directory, args.output_file, validate=not args.force + ) + + # Show warning if validation was skipped + if args.force: + print("Warning: Skipped validation, file may be corrupt", file=sys.stderr) + # Exit with error if validation failed + elif not success: + print("Contents would produce a corrupt file.", file=sys.stderr) + print("Please validate XML before repacking.", file=sys.stderr) + print("Use --force to skip validation and pack anyway.", file=sys.stderr) + sys.exit(1) + + except ValueError as e: + sys.exit(f"Error: {e}") + + +def pack_document(input_dir, output_file, validate=False): + """Pack a directory into an Office file (.docx/.pptx/.xlsx). + + Args: + input_dir: Path to unpacked Office document directory + output_file: Path to output Office file + validate: If True, validates with soffice (default: False) + + Returns: + bool: True if successful, False if validation failed + """ + input_dir = Path(input_dir) + output_file = Path(output_file) + + if not input_dir.is_dir(): + raise ValueError(f"{input_dir} is not a directory") + if output_file.suffix.lower() not in {".docx", ".pptx", ".xlsx"}: + raise ValueError(f"{output_file} must be a .docx, .pptx, or .xlsx file") + + # Work in temporary directory to avoid modifying original + with tempfile.TemporaryDirectory() as temp_dir: + temp_content_dir = Path(temp_dir) / "content" + shutil.copytree(input_dir, temp_content_dir) + + # Process XML files to remove pretty-printing whitespace + for pattern in ["*.xml", "*.rels"]: + for xml_file in temp_content_dir.rglob(pattern): + condense_xml(xml_file) + + # Create final Office file as zip archive + output_file.parent.mkdir(parents=True, exist_ok=True) + with zipfile.ZipFile(output_file, "w", zipfile.ZIP_DEFLATED) as zf: + for f in temp_content_dir.rglob("*"): + if f.is_file(): + zf.write(f, f.relative_to(temp_content_dir)) + + # Validate if requested + if validate: + if not validate_document(output_file): + output_file.unlink() # Delete the corrupt file + return False + + return True + + +def validate_document(doc_path): + """Validate document by converting to HTML with soffice.""" + # Determine the correct filter based on file extension + match doc_path.suffix.lower(): + case ".docx": + filter_name = "html:HTML" + case ".pptx": + filter_name = "html:impress_html_Export" + case ".xlsx": + filter_name = "html:HTML (StarCalc)" + + with tempfile.TemporaryDirectory() as temp_dir: + try: + result = subprocess.run( + [ + "soffice", + "--headless", + "--convert-to", + filter_name, + "--outdir", + temp_dir, + str(doc_path), + ], + capture_output=True, + timeout=10, + text=True, + ) + if not (Path(temp_dir) / f"{doc_path.stem}.html").exists(): + error_msg = result.stderr.strip() or "Document validation failed" + print(f"Validation error: {error_msg}", file=sys.stderr) + return False + return True + except FileNotFoundError: + print("Warning: soffice not found. Skipping validation.", file=sys.stderr) + return True + except subprocess.TimeoutExpired: + print("Validation error: Timeout during conversion", file=sys.stderr) + return False + except Exception as e: + print(f"Validation error: {e}", file=sys.stderr) + return False + + +def condense_xml(xml_file): + """Strip unnecessary whitespace and remove comments.""" + with open(xml_file, "r", encoding="utf-8") as f: + dom = defusedxml.minidom.parse(f) + + # Process each element to remove whitespace and comments + for element in dom.getElementsByTagName("*"): + # Skip w:t elements and their processing + if element.tagName.endswith(":t"): + continue + + # Remove whitespace-only text nodes and comment nodes + for child in list(element.childNodes): + if ( + child.nodeType == child.TEXT_NODE + and child.nodeValue + and child.nodeValue.strip() == "" + ) or child.nodeType == child.COMMENT_NODE: + element.removeChild(child) + + # Write back the condensed XML + with open(xml_file, "wb") as f: + f.write(dom.toxml(encoding="UTF-8")) + + +if __name__ == "__main__": + main() diff --git a/skills/pptx/ooxml/scripts/unpack.py b/skills/pptx/ooxml/scripts/unpack.py new file mode 100755 index 0000000..4938798 --- /dev/null +++ b/skills/pptx/ooxml/scripts/unpack.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +"""Unpack and format XML contents of Office files (.docx, .pptx, .xlsx)""" + +import random +import sys +import defusedxml.minidom +import zipfile +from pathlib import Path + +# Get command line arguments +assert len(sys.argv) == 3, "Usage: python unpack.py <office_file> <output_dir>" +input_file, output_dir = sys.argv[1], sys.argv[2] + +# Extract and format +output_path = Path(output_dir) +output_path.mkdir(parents=True, exist_ok=True) +zipfile.ZipFile(input_file).extractall(output_path) + +# Pretty print all XML files +xml_files = list(output_path.rglob("*.xml")) + list(output_path.rglob("*.rels")) +for xml_file in xml_files: + content = xml_file.read_text(encoding="utf-8") + dom = defusedxml.minidom.parseString(content) + xml_file.write_bytes(dom.toprettyxml(indent=" ", encoding="ascii")) + +# For .docx files, suggest an RSID for tracked changes +if input_file.endswith(".docx"): + suggested_rsid = "".join(random.choices("0123456789ABCDEF", k=8)) + print(f"Suggested RSID for edit session: {suggested_rsid}") diff --git a/skills/pptx/ooxml/scripts/validate.py b/skills/pptx/ooxml/scripts/validate.py new file mode 100755 index 0000000..508c589 --- /dev/null +++ b/skills/pptx/ooxml/scripts/validate.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +""" +Command line tool to validate Office document XML files against XSD schemas and tracked changes. + +Usage: + python validate.py <dir> --original <original_file> +""" + +import argparse +import sys +from pathlib import Path + +from validation import DOCXSchemaValidator, PPTXSchemaValidator, RedliningValidator + + +def main(): + parser = argparse.ArgumentParser(description="Validate Office document XML files") + parser.add_argument( + "unpacked_dir", + help="Path to unpacked Office document directory", + ) + parser.add_argument( + "--original", + required=True, + help="Path to original file (.docx/.pptx/.xlsx)", + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="Enable verbose output", + ) + args = parser.parse_args() + + # Validate paths + unpacked_dir = Path(args.unpacked_dir) + original_file = Path(args.original) + file_extension = original_file.suffix.lower() + assert unpacked_dir.is_dir(), f"Error: {unpacked_dir} is not a directory" + assert original_file.is_file(), f"Error: {original_file} is not a file" + assert file_extension in [".docx", ".pptx", ".xlsx"], ( + f"Error: {original_file} must be a .docx, .pptx, or .xlsx file" + ) + + # Run validations + match file_extension: + case ".docx": + validators = [DOCXSchemaValidator, RedliningValidator] + case ".pptx": + validators = [PPTXSchemaValidator] + case _: + print(f"Error: Validation not supported for file type {file_extension}") + sys.exit(1) + + # Run validators + success = True + for V in validators: + validator = V(unpacked_dir, original_file, verbose=args.verbose) + if not validator.validate(): + success = False + + if success: + print("All validations PASSED!") + + sys.exit(0 if success else 1) + + +if __name__ == "__main__": + main() diff --git a/skills/pptx/ooxml/scripts/validation/__init__.py b/skills/pptx/ooxml/scripts/validation/__init__.py new file mode 100755 index 0000000..db092ec --- /dev/null +++ b/skills/pptx/ooxml/scripts/validation/__init__.py @@ -0,0 +1,15 @@ +""" +Validation modules for Word document processing. +""" + +from .base import BaseSchemaValidator +from .docx import DOCXSchemaValidator +from .pptx import PPTXSchemaValidator +from .redlining import RedliningValidator + +__all__ = [ + "BaseSchemaValidator", + "DOCXSchemaValidator", + "PPTXSchemaValidator", + "RedliningValidator", +] diff --git a/skills/pptx/ooxml/scripts/validation/base.py b/skills/pptx/ooxml/scripts/validation/base.py new file mode 100755 index 0000000..0681b19 --- /dev/null +++ b/skills/pptx/ooxml/scripts/validation/base.py @@ -0,0 +1,951 @@ +""" +Base validator with common validation logic for document files. +""" + +import re +from pathlib import Path + +import lxml.etree + + +class BaseSchemaValidator: + """Base validator with common validation logic for document files.""" + + # Elements whose 'id' attributes must be unique within their file + # Format: element_name -> (attribute_name, scope) + # scope can be 'file' (unique within file) or 'global' (unique across all files) + UNIQUE_ID_REQUIREMENTS = { + # Word elements + "comment": ("id", "file"), # Comment IDs in comments.xml + "commentrangestart": ("id", "file"), # Must match comment IDs + "commentrangeend": ("id", "file"), # Must match comment IDs + "bookmarkstart": ("id", "file"), # Bookmark start IDs + "bookmarkend": ("id", "file"), # Bookmark end IDs + # Note: ins and del (track changes) can share IDs when part of same revision + # PowerPoint elements + "sldid": ("id", "file"), # Slide IDs in presentation.xml + "sldmasterid": ("id", "global"), # Slide master IDs must be globally unique + "sldlayoutid": ("id", "global"), # Slide layout IDs must be globally unique + "cm": ("authorid", "file"), # Comment author IDs + # Excel elements + "sheet": ("sheetid", "file"), # Sheet IDs in workbook.xml + "definedname": ("id", "file"), # Named range IDs + # Drawing/Shape elements (all formats) + "cxnsp": ("id", "file"), # Connection shape IDs + "sp": ("id", "file"), # Shape IDs + "pic": ("id", "file"), # Picture IDs + "grpsp": ("id", "file"), # Group shape IDs + } + + # Mapping of element names to expected relationship types + # Subclasses should override this with format-specific mappings + ELEMENT_RELATIONSHIP_TYPES = {} + + # Unified schema mappings for all Office document types + SCHEMA_MAPPINGS = { + # Document type specific schemas + "word": "ISO-IEC29500-4_2016/wml.xsd", # Word documents + "ppt": "ISO-IEC29500-4_2016/pml.xsd", # PowerPoint presentations + "xl": "ISO-IEC29500-4_2016/sml.xsd", # Excel spreadsheets + # Common file types + "[Content_Types].xml": "ecma/fouth-edition/opc-contentTypes.xsd", + "app.xml": "ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd", + "core.xml": "ecma/fouth-edition/opc-coreProperties.xsd", + "custom.xml": "ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd", + ".rels": "ecma/fouth-edition/opc-relationships.xsd", + # Word-specific files + "people.xml": "microsoft/wml-2012.xsd", + "commentsIds.xml": "microsoft/wml-cid-2016.xsd", + "commentsExtensible.xml": "microsoft/wml-cex-2018.xsd", + "commentsExtended.xml": "microsoft/wml-2012.xsd", + # Chart files (common across document types) + "chart": "ISO-IEC29500-4_2016/dml-chart.xsd", + # Theme files (common across document types) + "theme": "ISO-IEC29500-4_2016/dml-main.xsd", + # Drawing and media files + "drawing": "ISO-IEC29500-4_2016/dml-main.xsd", + } + + # Unified namespace constants + MC_NAMESPACE = "http://schemas.openxmlformats.org/markup-compatibility/2006" + XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace" + + # Common OOXML namespaces used across validators + PACKAGE_RELATIONSHIPS_NAMESPACE = ( + "http://schemas.openxmlformats.org/package/2006/relationships" + ) + OFFICE_RELATIONSHIPS_NAMESPACE = ( + "http://schemas.openxmlformats.org/officeDocument/2006/relationships" + ) + CONTENT_TYPES_NAMESPACE = ( + "http://schemas.openxmlformats.org/package/2006/content-types" + ) + + # Folders where we should clean ignorable namespaces + MAIN_CONTENT_FOLDERS = {"word", "ppt", "xl"} + + # All allowed OOXML namespaces (superset of all document types) + OOXML_NAMESPACES = { + "http://schemas.openxmlformats.org/officeDocument/2006/math", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + "http://schemas.openxmlformats.org/schemaLibrary/2006/main", + "http://schemas.openxmlformats.org/drawingml/2006/main", + "http://schemas.openxmlformats.org/drawingml/2006/chart", + "http://schemas.openxmlformats.org/drawingml/2006/chartDrawing", + "http://schemas.openxmlformats.org/drawingml/2006/diagram", + "http://schemas.openxmlformats.org/drawingml/2006/picture", + "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing", + "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", + "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + "http://schemas.openxmlformats.org/presentationml/2006/main", + "http://schemas.openxmlformats.org/spreadsheetml/2006/main", + "http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes", + "http://www.w3.org/XML/1998/namespace", + } + + def __init__(self, unpacked_dir, original_file, verbose=False): + self.unpacked_dir = Path(unpacked_dir).resolve() + self.original_file = Path(original_file) + self.verbose = verbose + + # Set schemas directory + self.schemas_dir = Path(__file__).parent.parent.parent / "schemas" + + # Get all XML and .rels files + patterns = ["*.xml", "*.rels"] + self.xml_files = [ + f for pattern in patterns for f in self.unpacked_dir.rglob(pattern) + ] + + if not self.xml_files: + print(f"Warning: No XML files found in {self.unpacked_dir}") + + def validate(self): + """Run all validation checks and return True if all pass.""" + raise NotImplementedError("Subclasses must implement the validate method") + + def validate_xml(self): + """Validate that all XML files are well-formed.""" + errors = [] + + for xml_file in self.xml_files: + try: + # Try to parse the XML file + lxml.etree.parse(str(xml_file)) + except lxml.etree.XMLSyntaxError as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {e.lineno}: {e.msg}" + ) + except Exception as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Unexpected error: {str(e)}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} XML violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All XML files are well-formed") + return True + + def validate_namespaces(self): + """Validate that namespace prefixes in Ignorable attributes are declared.""" + errors = [] + + for xml_file in self.xml_files: + try: + root = lxml.etree.parse(str(xml_file)).getroot() + declared = set(root.nsmap.keys()) - {None} # Exclude default namespace + + for attr_val in [ + v for k, v in root.attrib.items() if k.endswith("Ignorable") + ]: + undeclared = set(attr_val.split()) - declared + errors.extend( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Namespace '{ns}' in Ignorable but not declared" + for ns in undeclared + ) + except lxml.etree.XMLSyntaxError: + continue + + if errors: + print(f"FAILED - {len(errors)} namespace issues:") + for error in errors: + print(error) + return False + if self.verbose: + print("PASSED - All namespace prefixes properly declared") + return True + + def validate_unique_ids(self): + """Validate that specific IDs are unique according to OOXML requirements.""" + errors = [] + global_ids = {} # Track globally unique IDs across all files + + for xml_file in self.xml_files: + try: + root = lxml.etree.parse(str(xml_file)).getroot() + file_ids = {} # Track IDs that must be unique within this file + + # Remove all mc:AlternateContent elements from the tree + mc_elements = root.xpath( + ".//mc:AlternateContent", namespaces={"mc": self.MC_NAMESPACE} + ) + for elem in mc_elements: + elem.getparent().remove(elem) + + # Now check IDs in the cleaned tree + for elem in root.iter(): + # Get the element name without namespace + tag = ( + elem.tag.split("}")[-1].lower() + if "}" in elem.tag + else elem.tag.lower() + ) + + # Check if this element type has ID uniqueness requirements + if tag in self.UNIQUE_ID_REQUIREMENTS: + attr_name, scope = self.UNIQUE_ID_REQUIREMENTS[tag] + + # Look for the specified attribute + id_value = None + for attr, value in elem.attrib.items(): + attr_local = ( + attr.split("}")[-1].lower() + if "}" in attr + else attr.lower() + ) + if attr_local == attr_name: + id_value = value + break + + if id_value is not None: + if scope == "global": + # Check global uniqueness + if id_value in global_ids: + prev_file, prev_line, prev_tag = global_ids[ + id_value + ] + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: Global ID '{id_value}' in <{tag}> " + f"already used in {prev_file} at line {prev_line} in <{prev_tag}>" + ) + else: + global_ids[id_value] = ( + xml_file.relative_to(self.unpacked_dir), + elem.sourceline, + tag, + ) + elif scope == "file": + # Check file-level uniqueness + key = (tag, attr_name) + if key not in file_ids: + file_ids[key] = {} + + if id_value in file_ids[key]: + prev_line = file_ids[key][id_value] + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: Duplicate {attr_name}='{id_value}' in <{tag}> " + f"(first occurrence at line {prev_line})" + ) + else: + file_ids[key][id_value] = elem.sourceline + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} ID uniqueness violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All required IDs are unique") + return True + + def validate_file_references(self): + """ + Validate that all .rels files properly reference files and that all files are referenced. + """ + errors = [] + + # Find all .rels files + rels_files = list(self.unpacked_dir.rglob("*.rels")) + + if not rels_files: + if self.verbose: + print("PASSED - No .rels files found") + return True + + # Get all files in the unpacked directory (excluding reference files) + all_files = [] + for file_path in self.unpacked_dir.rglob("*"): + if ( + file_path.is_file() + and file_path.name != "[Content_Types].xml" + and not file_path.name.endswith(".rels") + ): # This file is not referenced by .rels + all_files.append(file_path.resolve()) + + # Track all files that are referenced by any .rels file + all_referenced_files = set() + + if self.verbose: + print( + f"Found {len(rels_files)} .rels files and {len(all_files)} target files" + ) + + # Check each .rels file + for rels_file in rels_files: + try: + # Parse relationships file + rels_root = lxml.etree.parse(str(rels_file)).getroot() + + # Get the directory where this .rels file is located + rels_dir = rels_file.parent + + # Find all relationships and their targets + referenced_files = set() + broken_refs = [] + + for rel in rels_root.findall( + ".//ns:Relationship", + namespaces={"ns": self.PACKAGE_RELATIONSHIPS_NAMESPACE}, + ): + target = rel.get("Target") + if target and not target.startswith( + ("http", "mailto:") + ): # Skip external URLs + # Resolve the target path relative to the .rels file location + if rels_file.name == ".rels": + # Root .rels file - targets are relative to unpacked_dir + target_path = self.unpacked_dir / target + else: + # Other .rels files - targets are relative to their parent's parent + # e.g., word/_rels/document.xml.rels -> targets relative to word/ + base_dir = rels_dir.parent + target_path = base_dir / target + + # Normalize the path and check if it exists + try: + target_path = target_path.resolve() + if target_path.exists() and target_path.is_file(): + referenced_files.add(target_path) + all_referenced_files.add(target_path) + else: + broken_refs.append((target, rel.sourceline)) + except (OSError, ValueError): + broken_refs.append((target, rel.sourceline)) + + # Report broken references + if broken_refs: + rel_path = rels_file.relative_to(self.unpacked_dir) + for broken_ref, line_num in broken_refs: + errors.append( + f" {rel_path}: Line {line_num}: Broken reference to {broken_ref}" + ) + + except Exception as e: + rel_path = rels_file.relative_to(self.unpacked_dir) + errors.append(f" Error parsing {rel_path}: {e}") + + # Check for unreferenced files (files that exist but are not referenced anywhere) + unreferenced_files = set(all_files) - all_referenced_files + + if unreferenced_files: + for unref_file in sorted(unreferenced_files): + unref_rel_path = unref_file.relative_to(self.unpacked_dir) + errors.append(f" Unreferenced file: {unref_rel_path}") + + if errors: + print(f"FAILED - Found {len(errors)} relationship validation errors:") + for error in errors: + print(error) + print( + "CRITICAL: These errors will cause the document to appear corrupt. " + + "Broken references MUST be fixed, " + + "and unreferenced files MUST be referenced or removed." + ) + return False + else: + if self.verbose: + print( + "PASSED - All references are valid and all files are properly referenced" + ) + return True + + def validate_all_relationship_ids(self): + """ + Validate that all r:id attributes in XML files reference existing IDs + in their corresponding .rels files, and optionally validate relationship types. + """ + import lxml.etree + + errors = [] + + # Process each XML file that might contain r:id references + for xml_file in self.xml_files: + # Skip .rels files themselves + if xml_file.suffix == ".rels": + continue + + # Determine the corresponding .rels file + # For dir/file.xml, it's dir/_rels/file.xml.rels + rels_dir = xml_file.parent / "_rels" + rels_file = rels_dir / f"{xml_file.name}.rels" + + # Skip if there's no corresponding .rels file (that's okay) + if not rels_file.exists(): + continue + + try: + # Parse the .rels file to get valid relationship IDs and their types + rels_root = lxml.etree.parse(str(rels_file)).getroot() + rid_to_type = {} + + for rel in rels_root.findall( + f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship" + ): + rid = rel.get("Id") + rel_type = rel.get("Type", "") + if rid: + # Check for duplicate rIds + if rid in rid_to_type: + rels_rel_path = rels_file.relative_to(self.unpacked_dir) + errors.append( + f" {rels_rel_path}: Line {rel.sourceline}: " + f"Duplicate relationship ID '{rid}' (IDs must be unique)" + ) + # Extract just the type name from the full URL + type_name = ( + rel_type.split("/")[-1] if "/" in rel_type else rel_type + ) + rid_to_type[rid] = type_name + + # Parse the XML file to find all r:id references + xml_root = lxml.etree.parse(str(xml_file)).getroot() + + # Find all elements with r:id attributes + for elem in xml_root.iter(): + # Check for r:id attribute (relationship ID) + rid_attr = elem.get(f"{{{self.OFFICE_RELATIONSHIPS_NAMESPACE}}}id") + if rid_attr: + xml_rel_path = xml_file.relative_to(self.unpacked_dir) + elem_name = ( + elem.tag.split("}")[-1] if "}" in elem.tag else elem.tag + ) + + # Check if the ID exists + if rid_attr not in rid_to_type: + errors.append( + f" {xml_rel_path}: Line {elem.sourceline}: " + f"<{elem_name}> references non-existent relationship '{rid_attr}' " + f"(valid IDs: {', '.join(sorted(rid_to_type.keys())[:5])}{'...' if len(rid_to_type) > 5 else ''})" + ) + # Check if we have type expectations for this element + elif self.ELEMENT_RELATIONSHIP_TYPES: + expected_type = self._get_expected_relationship_type( + elem_name + ) + if expected_type: + actual_type = rid_to_type[rid_attr] + # Check if the actual type matches or contains the expected type + if expected_type not in actual_type.lower(): + errors.append( + f" {xml_rel_path}: Line {elem.sourceline}: " + f"<{elem_name}> references '{rid_attr}' which points to '{actual_type}' " + f"but should point to a '{expected_type}' relationship" + ) + + except Exception as e: + xml_rel_path = xml_file.relative_to(self.unpacked_dir) + errors.append(f" Error processing {xml_rel_path}: {e}") + + if errors: + print(f"FAILED - Found {len(errors)} relationship ID reference errors:") + for error in errors: + print(error) + print("\nThese ID mismatches will cause the document to appear corrupt!") + return False + else: + if self.verbose: + print("PASSED - All relationship ID references are valid") + return True + + def _get_expected_relationship_type(self, element_name): + """ + Get the expected relationship type for an element. + First checks the explicit mapping, then tries pattern detection. + """ + # Normalize element name to lowercase + elem_lower = element_name.lower() + + # Check explicit mapping first + if elem_lower in self.ELEMENT_RELATIONSHIP_TYPES: + return self.ELEMENT_RELATIONSHIP_TYPES[elem_lower] + + # Try pattern detection for common patterns + # Pattern 1: Elements ending in "Id" often expect a relationship of the prefix type + if elem_lower.endswith("id") and len(elem_lower) > 2: + # e.g., "sldId" -> "sld", "sldMasterId" -> "sldMaster" + prefix = elem_lower[:-2] # Remove "id" + # Check if this might be a compound like "sldMasterId" + if prefix.endswith("master"): + return prefix.lower() + elif prefix.endswith("layout"): + return prefix.lower() + else: + # Simple case like "sldId" -> "slide" + # Common transformations + if prefix == "sld": + return "slide" + return prefix.lower() + + # Pattern 2: Elements ending in "Reference" expect a relationship of the prefix type + if elem_lower.endswith("reference") and len(elem_lower) > 9: + prefix = elem_lower[:-9] # Remove "reference" + return prefix.lower() + + return None + + def validate_content_types(self): + """Validate that all content files are properly declared in [Content_Types].xml.""" + errors = [] + + # Find [Content_Types].xml file + content_types_file = self.unpacked_dir / "[Content_Types].xml" + if not content_types_file.exists(): + print("FAILED - [Content_Types].xml file not found") + return False + + try: + # Parse and get all declared parts and extensions + root = lxml.etree.parse(str(content_types_file)).getroot() + declared_parts = set() + declared_extensions = set() + + # Get Override declarations (specific files) + for override in root.findall( + f".//{{{self.CONTENT_TYPES_NAMESPACE}}}Override" + ): + part_name = override.get("PartName") + if part_name is not None: + declared_parts.add(part_name.lstrip("/")) + + # Get Default declarations (by extension) + for default in root.findall( + f".//{{{self.CONTENT_TYPES_NAMESPACE}}}Default" + ): + extension = default.get("Extension") + if extension is not None: + declared_extensions.add(extension.lower()) + + # Root elements that require content type declaration + declarable_roots = { + "sld", + "sldLayout", + "sldMaster", + "presentation", # PowerPoint + "document", # Word + "workbook", + "worksheet", # Excel + "theme", # Common + } + + # Common media file extensions that should be declared + media_extensions = { + "png": "image/png", + "jpg": "image/jpeg", + "jpeg": "image/jpeg", + "gif": "image/gif", + "bmp": "image/bmp", + "tiff": "image/tiff", + "wmf": "image/x-wmf", + "emf": "image/x-emf", + } + + # Get all files in the unpacked directory + all_files = list(self.unpacked_dir.rglob("*")) + all_files = [f for f in all_files if f.is_file()] + + # Check all XML files for Override declarations + for xml_file in self.xml_files: + path_str = str(xml_file.relative_to(self.unpacked_dir)).replace( + "\\", "/" + ) + + # Skip non-content files + if any( + skip in path_str + for skip in [".rels", "[Content_Types]", "docProps/", "_rels/"] + ): + continue + + try: + root_tag = lxml.etree.parse(str(xml_file)).getroot().tag + root_name = root_tag.split("}")[-1] if "}" in root_tag else root_tag + + if root_name in declarable_roots and path_str not in declared_parts: + errors.append( + f" {path_str}: File with <{root_name}> root not declared in [Content_Types].xml" + ) + + except Exception: + continue # Skip unparseable files + + # Check all non-XML files for Default extension declarations + for file_path in all_files: + # Skip XML files and metadata files (already checked above) + if file_path.suffix.lower() in {".xml", ".rels"}: + continue + if file_path.name == "[Content_Types].xml": + continue + if "_rels" in file_path.parts or "docProps" in file_path.parts: + continue + + extension = file_path.suffix.lstrip(".").lower() + if extension and extension not in declared_extensions: + # Check if it's a known media extension that should be declared + if extension in media_extensions: + relative_path = file_path.relative_to(self.unpacked_dir) + errors.append( + f' {relative_path}: File with extension \'{extension}\' not declared in [Content_Types].xml - should add: <Default Extension="{extension}" ContentType="{media_extensions[extension]}"/>' + ) + + except Exception as e: + errors.append(f" Error parsing [Content_Types].xml: {e}") + + if errors: + print(f"FAILED - Found {len(errors)} content type declaration errors:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print( + "PASSED - All content files are properly declared in [Content_Types].xml" + ) + return True + + def validate_file_against_xsd(self, xml_file, verbose=False): + """Validate a single XML file against XSD schema, comparing with original. + + Args: + xml_file: Path to XML file to validate + verbose: Enable verbose output + + Returns: + tuple: (is_valid, new_errors_set) where is_valid is True/False/None (skipped) + """ + # Resolve both paths to handle symlinks + xml_file = Path(xml_file).resolve() + unpacked_dir = self.unpacked_dir.resolve() + + # Validate current file + is_valid, current_errors = self._validate_single_file_xsd( + xml_file, unpacked_dir + ) + + if is_valid is None: + return None, set() # Skipped + elif is_valid: + return True, set() # Valid, no errors + + # Get errors from original file for this specific file + original_errors = self._get_original_file_errors(xml_file) + + # Compare with original (both are guaranteed to be sets here) + assert current_errors is not None + new_errors = current_errors - original_errors + + if new_errors: + if verbose: + relative_path = xml_file.relative_to(unpacked_dir) + print(f"FAILED - {relative_path}: {len(new_errors)} new error(s)") + for error in list(new_errors)[:3]: + truncated = error[:250] + "..." if len(error) > 250 else error + print(f" - {truncated}") + return False, new_errors + else: + # All errors existed in original + if verbose: + print( + f"PASSED - No new errors (original had {len(current_errors)} errors)" + ) + return True, set() + + def validate_against_xsd(self): + """Validate XML files against XSD schemas, showing only new errors compared to original.""" + new_errors = [] + original_error_count = 0 + valid_count = 0 + skipped_count = 0 + + for xml_file in self.xml_files: + relative_path = str(xml_file.relative_to(self.unpacked_dir)) + is_valid, new_file_errors = self.validate_file_against_xsd( + xml_file, verbose=False + ) + + if is_valid is None: + skipped_count += 1 + continue + elif is_valid and not new_file_errors: + valid_count += 1 + continue + elif is_valid: + # Had errors but all existed in original + original_error_count += 1 + valid_count += 1 + continue + + # Has new errors + new_errors.append(f" {relative_path}: {len(new_file_errors)} new error(s)") + for error in list(new_file_errors)[:3]: # Show first 3 errors + new_errors.append( + f" - {error[:250]}..." if len(error) > 250 else f" - {error}" + ) + + # Print summary + if self.verbose: + print(f"Validated {len(self.xml_files)} files:") + print(f" - Valid: {valid_count}") + print(f" - Skipped (no schema): {skipped_count}") + if original_error_count: + print(f" - With original errors (ignored): {original_error_count}") + print( + f" - With NEW errors: {len(new_errors) > 0 and len([e for e in new_errors if not e.startswith(' ')]) or 0}" + ) + + if new_errors: + print("\nFAILED - Found NEW validation errors:") + for error in new_errors: + print(error) + return False + else: + if self.verbose: + print("\nPASSED - No new XSD validation errors introduced") + return True + + def _get_schema_path(self, xml_file): + """Determine the appropriate schema path for an XML file.""" + # Check exact filename match + if xml_file.name in self.SCHEMA_MAPPINGS: + return self.schemas_dir / self.SCHEMA_MAPPINGS[xml_file.name] + + # Check .rels files + if xml_file.suffix == ".rels": + return self.schemas_dir / self.SCHEMA_MAPPINGS[".rels"] + + # Check chart files + if "charts/" in str(xml_file) and xml_file.name.startswith("chart"): + return self.schemas_dir / self.SCHEMA_MAPPINGS["chart"] + + # Check theme files + if "theme/" in str(xml_file) and xml_file.name.startswith("theme"): + return self.schemas_dir / self.SCHEMA_MAPPINGS["theme"] + + # Check if file is in a main content folder and use appropriate schema + if xml_file.parent.name in self.MAIN_CONTENT_FOLDERS: + return self.schemas_dir / self.SCHEMA_MAPPINGS[xml_file.parent.name] + + return None + + def _clean_ignorable_namespaces(self, xml_doc): + """Remove attributes and elements not in allowed namespaces.""" + # Create a clean copy + xml_string = lxml.etree.tostring(xml_doc, encoding="unicode") + xml_copy = lxml.etree.fromstring(xml_string) + + # Remove attributes not in allowed namespaces + for elem in xml_copy.iter(): + attrs_to_remove = [] + + for attr in elem.attrib: + # Check if attribute is from a namespace other than allowed ones + if "{" in attr: + ns = attr.split("}")[0][1:] + if ns not in self.OOXML_NAMESPACES: + attrs_to_remove.append(attr) + + # Remove collected attributes + for attr in attrs_to_remove: + del elem.attrib[attr] + + # Remove elements not in allowed namespaces + self._remove_ignorable_elements(xml_copy) + + return lxml.etree.ElementTree(xml_copy) + + def _remove_ignorable_elements(self, root): + """Recursively remove all elements not in allowed namespaces.""" + elements_to_remove = [] + + # Find elements to remove + for elem in list(root): + # Skip non-element nodes (comments, processing instructions, etc.) + if not hasattr(elem, "tag") or callable(elem.tag): + continue + + tag_str = str(elem.tag) + if tag_str.startswith("{"): + ns = tag_str.split("}")[0][1:] + if ns not in self.OOXML_NAMESPACES: + elements_to_remove.append(elem) + continue + + # Recursively clean child elements + self._remove_ignorable_elements(elem) + + # Remove collected elements + for elem in elements_to_remove: + root.remove(elem) + + def _preprocess_for_mc_ignorable(self, xml_doc): + """Preprocess XML to handle mc:Ignorable attribute properly.""" + # Remove mc:Ignorable attributes before validation + root = xml_doc.getroot() + + # Remove mc:Ignorable attribute from root + if f"{{{self.MC_NAMESPACE}}}Ignorable" in root.attrib: + del root.attrib[f"{{{self.MC_NAMESPACE}}}Ignorable"] + + return xml_doc + + def _validate_single_file_xsd(self, xml_file, base_path): + """Validate a single XML file against XSD schema. Returns (is_valid, errors_set).""" + schema_path = self._get_schema_path(xml_file) + if not schema_path: + return None, None # Skip file + + try: + # Load schema + with open(schema_path, "rb") as xsd_file: + parser = lxml.etree.XMLParser() + xsd_doc = lxml.etree.parse( + xsd_file, parser=parser, base_url=str(schema_path) + ) + schema = lxml.etree.XMLSchema(xsd_doc) + + # Load and preprocess XML + with open(xml_file, "r") as f: + xml_doc = lxml.etree.parse(f) + + xml_doc, _ = self._remove_template_tags_from_text_nodes(xml_doc) + xml_doc = self._preprocess_for_mc_ignorable(xml_doc) + + # Clean ignorable namespaces if needed + relative_path = xml_file.relative_to(base_path) + if ( + relative_path.parts + and relative_path.parts[0] in self.MAIN_CONTENT_FOLDERS + ): + xml_doc = self._clean_ignorable_namespaces(xml_doc) + + # Validate + if schema.validate(xml_doc): + return True, set() + else: + errors = set() + for error in schema.error_log: + # Store normalized error message (without line numbers for comparison) + errors.add(error.message) + return False, errors + + except Exception as e: + return False, {str(e)} + + def _get_original_file_errors(self, xml_file): + """Get XSD validation errors from a single file in the original document. + + Args: + xml_file: Path to the XML file in unpacked_dir to check + + Returns: + set: Set of error messages from the original file + """ + import tempfile + import zipfile + + # Resolve both paths to handle symlinks (e.g., /var vs /private/var on macOS) + xml_file = Path(xml_file).resolve() + unpacked_dir = self.unpacked_dir.resolve() + relative_path = xml_file.relative_to(unpacked_dir) + + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + + # Extract original file + with zipfile.ZipFile(self.original_file, "r") as zip_ref: + zip_ref.extractall(temp_path) + + # Find corresponding file in original + original_xml_file = temp_path / relative_path + + if not original_xml_file.exists(): + # File didn't exist in original, so no original errors + return set() + + # Validate the specific file in original + is_valid, errors = self._validate_single_file_xsd( + original_xml_file, temp_path + ) + return errors if errors else set() + + def _remove_template_tags_from_text_nodes(self, xml_doc): + """Remove template tags from XML text nodes and collect warnings. + + Template tags follow the pattern {{ ... }} and are used as placeholders + for content replacement. They should be removed from text content before + XSD validation while preserving XML structure. + + Returns: + tuple: (cleaned_xml_doc, warnings_list) + """ + warnings = [] + template_pattern = re.compile(r"\{\{[^}]*\}\}") + + # Create a copy of the document to avoid modifying the original + xml_string = lxml.etree.tostring(xml_doc, encoding="unicode") + xml_copy = lxml.etree.fromstring(xml_string) + + def process_text_content(text, content_type): + if not text: + return text + matches = list(template_pattern.finditer(text)) + if matches: + for match in matches: + warnings.append( + f"Found template tag in {content_type}: {match.group()}" + ) + return template_pattern.sub("", text) + return text + + # Process all text nodes in the document + for elem in xml_copy.iter(): + # Skip processing if this is a w:t element + if not hasattr(elem, "tag") or callable(elem.tag): + continue + tag_str = str(elem.tag) + if tag_str.endswith("}t") or tag_str == "t": + continue + + elem.text = process_text_content(elem.text, "text content") + elem.tail = process_text_content(elem.tail, "tail content") + + return lxml.etree.ElementTree(xml_copy), warnings + + +if __name__ == "__main__": + raise RuntimeError("This module should not be run directly.") diff --git a/skills/pptx/ooxml/scripts/validation/docx.py b/skills/pptx/ooxml/scripts/validation/docx.py new file mode 100755 index 0000000..602c470 --- /dev/null +++ b/skills/pptx/ooxml/scripts/validation/docx.py @@ -0,0 +1,274 @@ +""" +Validator for Word document XML files against XSD schemas. +""" + +import re +import tempfile +import zipfile + +import lxml.etree + +from .base import BaseSchemaValidator + + +class DOCXSchemaValidator(BaseSchemaValidator): + """Validator for Word document XML files against XSD schemas.""" + + # Word-specific namespace + WORD_2006_NAMESPACE = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" + + # Word-specific element to relationship type mappings + # Start with empty mapping - add specific cases as we discover them + ELEMENT_RELATIONSHIP_TYPES = {} + + def validate(self): + """Run all validation checks and return True if all pass.""" + # Test 0: XML well-formedness + if not self.validate_xml(): + return False + + # Test 1: Namespace declarations + all_valid = True + if not self.validate_namespaces(): + all_valid = False + + # Test 2: Unique IDs + if not self.validate_unique_ids(): + all_valid = False + + # Test 3: Relationship and file reference validation + if not self.validate_file_references(): + all_valid = False + + # Test 4: Content type declarations + if not self.validate_content_types(): + all_valid = False + + # Test 5: XSD schema validation + if not self.validate_against_xsd(): + all_valid = False + + # Test 6: Whitespace preservation + if not self.validate_whitespace_preservation(): + all_valid = False + + # Test 7: Deletion validation + if not self.validate_deletions(): + all_valid = False + + # Test 8: Insertion validation + if not self.validate_insertions(): + all_valid = False + + # Test 9: Relationship ID reference validation + if not self.validate_all_relationship_ids(): + all_valid = False + + # Count and compare paragraphs + self.compare_paragraph_counts() + + return all_valid + + def validate_whitespace_preservation(self): + """ + Validate that w:t elements with whitespace have xml:space='preserve'. + """ + errors = [] + + for xml_file in self.xml_files: + # Only check document.xml files + if xml_file.name != "document.xml": + continue + + try: + root = lxml.etree.parse(str(xml_file)).getroot() + + # Find all w:t elements + for elem in root.iter(f"{{{self.WORD_2006_NAMESPACE}}}t"): + if elem.text: + text = elem.text + # Check if text starts or ends with whitespace + if re.match(r"^\s.*", text) or re.match(r".*\s$", text): + # Check if xml:space="preserve" attribute exists + xml_space_attr = f"{{{self.XML_NAMESPACE}}}space" + if ( + xml_space_attr not in elem.attrib + or elem.attrib[xml_space_attr] != "preserve" + ): + # Show a preview of the text + text_preview = ( + repr(text)[:50] + "..." + if len(repr(text)) > 50 + else repr(text) + ) + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: w:t element with whitespace missing xml:space='preserve': {text_preview}" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} whitespace preservation violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All whitespace is properly preserved") + return True + + def validate_deletions(self): + """ + Validate that w:t elements are not within w:del elements. + For some reason, XSD validation does not catch this, so we do it manually. + """ + errors = [] + + for xml_file in self.xml_files: + # Only check document.xml files + if xml_file.name != "document.xml": + continue + + try: + root = lxml.etree.parse(str(xml_file)).getroot() + + # Find all w:t elements that are descendants of w:del elements + namespaces = {"w": self.WORD_2006_NAMESPACE} + xpath_expression = ".//w:del//w:t" + problematic_t_elements = root.xpath( + xpath_expression, namespaces=namespaces + ) + for t_elem in problematic_t_elements: + if t_elem.text: + # Show a preview of the text + text_preview = ( + repr(t_elem.text)[:50] + "..." + if len(repr(t_elem.text)) > 50 + else repr(t_elem.text) + ) + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {t_elem.sourceline}: <w:t> found within <w:del>: {text_preview}" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} deletion validation violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - No w:t elements found within w:del elements") + return True + + def count_paragraphs_in_unpacked(self): + """Count the number of paragraphs in the unpacked document.""" + count = 0 + + for xml_file in self.xml_files: + # Only check document.xml files + if xml_file.name != "document.xml": + continue + + try: + root = lxml.etree.parse(str(xml_file)).getroot() + # Count all w:p elements + paragraphs = root.findall(f".//{{{self.WORD_2006_NAMESPACE}}}p") + count = len(paragraphs) + except Exception as e: + print(f"Error counting paragraphs in unpacked document: {e}") + + return count + + def count_paragraphs_in_original(self): + """Count the number of paragraphs in the original docx file.""" + count = 0 + + try: + # Create temporary directory to unpack original + with tempfile.TemporaryDirectory() as temp_dir: + # Unpack original docx + with zipfile.ZipFile(self.original_file, "r") as zip_ref: + zip_ref.extractall(temp_dir) + + # Parse document.xml + doc_xml_path = temp_dir + "/word/document.xml" + root = lxml.etree.parse(doc_xml_path).getroot() + + # Count all w:p elements + paragraphs = root.findall(f".//{{{self.WORD_2006_NAMESPACE}}}p") + count = len(paragraphs) + + except Exception as e: + print(f"Error counting paragraphs in original document: {e}") + + return count + + def validate_insertions(self): + """ + Validate that w:delText elements are not within w:ins elements. + w:delText is only allowed in w:ins if nested within a w:del. + """ + errors = [] + + for xml_file in self.xml_files: + if xml_file.name != "document.xml": + continue + + try: + root = lxml.etree.parse(str(xml_file)).getroot() + namespaces = {"w": self.WORD_2006_NAMESPACE} + + # Find w:delText in w:ins that are NOT within w:del + invalid_elements = root.xpath( + ".//w:ins//w:delText[not(ancestor::w:del)]", + namespaces=namespaces + ) + + for elem in invalid_elements: + text_preview = ( + repr(elem.text or "")[:50] + "..." + if len(repr(elem.text or "")) > 50 + else repr(elem.text or "") + ) + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: <w:delText> within <w:ins>: {text_preview}" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} insertion validation violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - No w:delText elements within w:ins elements") + return True + + def compare_paragraph_counts(self): + """Compare paragraph counts between original and new document.""" + original_count = self.count_paragraphs_in_original() + new_count = self.count_paragraphs_in_unpacked() + + diff = new_count - original_count + diff_str = f"+{diff}" if diff > 0 else str(diff) + print(f"\nParagraphs: {original_count} → {new_count} ({diff_str})") + + +if __name__ == "__main__": + raise RuntimeError("This module should not be run directly.") diff --git a/skills/pptx/ooxml/scripts/validation/pptx.py b/skills/pptx/ooxml/scripts/validation/pptx.py new file mode 100755 index 0000000..66d5b1e --- /dev/null +++ b/skills/pptx/ooxml/scripts/validation/pptx.py @@ -0,0 +1,315 @@ +""" +Validator for PowerPoint presentation XML files against XSD schemas. +""" + +import re + +from .base import BaseSchemaValidator + + +class PPTXSchemaValidator(BaseSchemaValidator): + """Validator for PowerPoint presentation XML files against XSD schemas.""" + + # PowerPoint presentation namespace + PRESENTATIONML_NAMESPACE = ( + "http://schemas.openxmlformats.org/presentationml/2006/main" + ) + + # PowerPoint-specific element to relationship type mappings + ELEMENT_RELATIONSHIP_TYPES = { + "sldid": "slide", + "sldmasterid": "slidemaster", + "notesmasterid": "notesmaster", + "sldlayoutid": "slidelayout", + "themeid": "theme", + "tablestyleid": "tablestyles", + } + + def validate(self): + """Run all validation checks and return True if all pass.""" + # Test 0: XML well-formedness + if not self.validate_xml(): + return False + + # Test 1: Namespace declarations + all_valid = True + if not self.validate_namespaces(): + all_valid = False + + # Test 2: Unique IDs + if not self.validate_unique_ids(): + all_valid = False + + # Test 3: UUID ID validation + if not self.validate_uuid_ids(): + all_valid = False + + # Test 4: Relationship and file reference validation + if not self.validate_file_references(): + all_valid = False + + # Test 5: Slide layout ID validation + if not self.validate_slide_layout_ids(): + all_valid = False + + # Test 6: Content type declarations + if not self.validate_content_types(): + all_valid = False + + # Test 7: XSD schema validation + if not self.validate_against_xsd(): + all_valid = False + + # Test 8: Notes slide reference validation + if not self.validate_notes_slide_references(): + all_valid = False + + # Test 9: Relationship ID reference validation + if not self.validate_all_relationship_ids(): + all_valid = False + + # Test 10: Duplicate slide layout references validation + if not self.validate_no_duplicate_slide_layouts(): + all_valid = False + + return all_valid + + def validate_uuid_ids(self): + """Validate that ID attributes that look like UUIDs contain only hex values.""" + import lxml.etree + + errors = [] + # UUID pattern: 8-4-4-4-12 hex digits with optional braces/hyphens + uuid_pattern = re.compile( + r"^[\{\(]?[0-9A-Fa-f]{8}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{12}[\}\)]?$" + ) + + for xml_file in self.xml_files: + try: + root = lxml.etree.parse(str(xml_file)).getroot() + + # Check all elements for ID attributes + for elem in root.iter(): + for attr, value in elem.attrib.items(): + # Check if this is an ID attribute + attr_name = attr.split("}")[-1].lower() + if attr_name == "id" or attr_name.endswith("id"): + # Check if value looks like a UUID (has the right length and pattern structure) + if self._looks_like_uuid(value): + # Validate that it contains only hex characters in the right positions + if not uuid_pattern.match(value): + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: ID '{value}' appears to be a UUID but contains invalid hex characters" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} UUID ID validation errors:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All UUID-like IDs contain valid hex values") + return True + + def _looks_like_uuid(self, value): + """Check if a value has the general structure of a UUID.""" + # Remove common UUID delimiters + clean_value = value.strip("{}()").replace("-", "") + # Check if it's 32 hex-like characters (could include invalid hex chars) + return len(clean_value) == 32 and all(c.isalnum() for c in clean_value) + + def validate_slide_layout_ids(self): + """Validate that sldLayoutId elements in slide masters reference valid slide layouts.""" + import lxml.etree + + errors = [] + + # Find all slide master files + slide_masters = list(self.unpacked_dir.glob("ppt/slideMasters/*.xml")) + + if not slide_masters: + if self.verbose: + print("PASSED - No slide masters found") + return True + + for slide_master in slide_masters: + try: + # Parse the slide master file + root = lxml.etree.parse(str(slide_master)).getroot() + + # Find the corresponding _rels file for this slide master + rels_file = slide_master.parent / "_rels" / f"{slide_master.name}.rels" + + if not rels_file.exists(): + errors.append( + f" {slide_master.relative_to(self.unpacked_dir)}: " + f"Missing relationships file: {rels_file.relative_to(self.unpacked_dir)}" + ) + continue + + # Parse the relationships file + rels_root = lxml.etree.parse(str(rels_file)).getroot() + + # Build a set of valid relationship IDs that point to slide layouts + valid_layout_rids = set() + for rel in rels_root.findall( + f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship" + ): + rel_type = rel.get("Type", "") + if "slideLayout" in rel_type: + valid_layout_rids.add(rel.get("Id")) + + # Find all sldLayoutId elements in the slide master + for sld_layout_id in root.findall( + f".//{{{self.PRESENTATIONML_NAMESPACE}}}sldLayoutId" + ): + r_id = sld_layout_id.get( + f"{{{self.OFFICE_RELATIONSHIPS_NAMESPACE}}}id" + ) + layout_id = sld_layout_id.get("id") + + if r_id and r_id not in valid_layout_rids: + errors.append( + f" {slide_master.relative_to(self.unpacked_dir)}: " + f"Line {sld_layout_id.sourceline}: sldLayoutId with id='{layout_id}' " + f"references r:id='{r_id}' which is not found in slide layout relationships" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {slide_master.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} slide layout ID validation errors:") + for error in errors: + print(error) + print( + "Remove invalid references or add missing slide layouts to the relationships file." + ) + return False + else: + if self.verbose: + print("PASSED - All slide layout IDs reference valid slide layouts") + return True + + def validate_no_duplicate_slide_layouts(self): + """Validate that each slide has exactly one slideLayout reference.""" + import lxml.etree + + errors = [] + slide_rels_files = list(self.unpacked_dir.glob("ppt/slides/_rels/*.xml.rels")) + + for rels_file in slide_rels_files: + try: + root = lxml.etree.parse(str(rels_file)).getroot() + + # Find all slideLayout relationships + layout_rels = [ + rel + for rel in root.findall( + f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship" + ) + if "slideLayout" in rel.get("Type", "") + ] + + if len(layout_rels) > 1: + errors.append( + f" {rels_file.relative_to(self.unpacked_dir)}: has {len(layout_rels)} slideLayout references" + ) + + except Exception as e: + errors.append( + f" {rels_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print("FAILED - Found slides with duplicate slideLayout references:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All slides have exactly one slideLayout reference") + return True + + def validate_notes_slide_references(self): + """Validate that each notesSlide file is referenced by only one slide.""" + import lxml.etree + + errors = [] + notes_slide_references = {} # Track which slides reference each notesSlide + + # Find all slide relationship files + slide_rels_files = list(self.unpacked_dir.glob("ppt/slides/_rels/*.xml.rels")) + + if not slide_rels_files: + if self.verbose: + print("PASSED - No slide relationship files found") + return True + + for rels_file in slide_rels_files: + try: + # Parse the relationships file + root = lxml.etree.parse(str(rels_file)).getroot() + + # Find all notesSlide relationships + for rel in root.findall( + f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship" + ): + rel_type = rel.get("Type", "") + if "notesSlide" in rel_type: + target = rel.get("Target", "") + if target: + # Normalize the target path to handle relative paths + normalized_target = target.replace("../", "") + + # Track which slide references this notesSlide + slide_name = rels_file.stem.replace( + ".xml", "" + ) # e.g., "slide1" + + if normalized_target not in notes_slide_references: + notes_slide_references[normalized_target] = [] + notes_slide_references[normalized_target].append( + (slide_name, rels_file) + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {rels_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + # Check for duplicate references + for target, references in notes_slide_references.items(): + if len(references) > 1: + slide_names = [ref[0] for ref in references] + errors.append( + f" Notes slide '{target}' is referenced by multiple slides: {', '.join(slide_names)}" + ) + for slide_name, rels_file in references: + errors.append(f" - {rels_file.relative_to(self.unpacked_dir)}") + + if errors: + print( + f"FAILED - Found {len([e for e in errors if not e.startswith(' ')])} notes slide reference validation errors:" + ) + for error in errors: + print(error) + print("Each slide may optionally have its own slide file.") + return False + else: + if self.verbose: + print("PASSED - All notes slide references are unique") + return True + + +if __name__ == "__main__": + raise RuntimeError("This module should not be run directly.") diff --git a/skills/pptx/ooxml/scripts/validation/redlining.py b/skills/pptx/ooxml/scripts/validation/redlining.py new file mode 100755 index 0000000..7ed425e --- /dev/null +++ b/skills/pptx/ooxml/scripts/validation/redlining.py @@ -0,0 +1,279 @@ +""" +Validator for tracked changes in Word documents. +""" + +import subprocess +import tempfile +import zipfile +from pathlib import Path + + +class RedliningValidator: + """Validator for tracked changes in Word documents.""" + + def __init__(self, unpacked_dir, original_docx, verbose=False): + self.unpacked_dir = Path(unpacked_dir) + self.original_docx = Path(original_docx) + self.verbose = verbose + self.namespaces = { + "w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main" + } + + def validate(self): + """Main validation method that returns True if valid, False otherwise.""" + # Verify unpacked directory exists and has correct structure + modified_file = self.unpacked_dir / "word" / "document.xml" + if not modified_file.exists(): + print(f"FAILED - Modified document.xml not found at {modified_file}") + return False + + # First, check if there are any tracked changes by Claude to validate + try: + import xml.etree.ElementTree as ET + + tree = ET.parse(modified_file) + root = tree.getroot() + + # Check for w:del or w:ins tags authored by Claude + del_elements = root.findall(".//w:del", self.namespaces) + ins_elements = root.findall(".//w:ins", self.namespaces) + + # Filter to only include changes by Claude + claude_del_elements = [ + elem + for elem in del_elements + if elem.get(f"{{{self.namespaces['w']}}}author") == "Claude" + ] + claude_ins_elements = [ + elem + for elem in ins_elements + if elem.get(f"{{{self.namespaces['w']}}}author") == "Claude" + ] + + # Redlining validation is only needed if tracked changes by Claude have been used. + if not claude_del_elements and not claude_ins_elements: + if self.verbose: + print("PASSED - No tracked changes by Claude found.") + return True + + except Exception: + # If we can't parse the XML, continue with full validation + pass + + # Create temporary directory for unpacking original docx + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + + # Unpack original docx + try: + with zipfile.ZipFile(self.original_docx, "r") as zip_ref: + zip_ref.extractall(temp_path) + except Exception as e: + print(f"FAILED - Error unpacking original docx: {e}") + return False + + original_file = temp_path / "word" / "document.xml" + if not original_file.exists(): + print( + f"FAILED - Original document.xml not found in {self.original_docx}" + ) + return False + + # Parse both XML files using xml.etree.ElementTree for redlining validation + try: + import xml.etree.ElementTree as ET + + modified_tree = ET.parse(modified_file) + modified_root = modified_tree.getroot() + original_tree = ET.parse(original_file) + original_root = original_tree.getroot() + except ET.ParseError as e: + print(f"FAILED - Error parsing XML files: {e}") + return False + + # Remove Claude's tracked changes from both documents + self._remove_claude_tracked_changes(original_root) + self._remove_claude_tracked_changes(modified_root) + + # Extract and compare text content + modified_text = self._extract_text_content(modified_root) + original_text = self._extract_text_content(original_root) + + if modified_text != original_text: + # Show detailed character-level differences for each paragraph + error_message = self._generate_detailed_diff( + original_text, modified_text + ) + print(error_message) + return False + + if self.verbose: + print("PASSED - All changes by Claude are properly tracked") + return True + + def _generate_detailed_diff(self, original_text, modified_text): + """Generate detailed word-level differences using git word diff.""" + error_parts = [ + "FAILED - Document text doesn't match after removing Claude's tracked changes", + "", + "Likely causes:", + " 1. Modified text inside another author's <w:ins> or <w:del> tags", + " 2. Made edits without proper tracked changes", + " 3. Didn't nest <w:del> inside <w:ins> when deleting another's insertion", + "", + "For pre-redlined documents, use correct patterns:", + " - To reject another's INSERTION: Nest <w:del> inside their <w:ins>", + " - To restore another's DELETION: Add new <w:ins> AFTER their <w:del>", + "", + ] + + # Show git word diff + git_diff = self._get_git_word_diff(original_text, modified_text) + if git_diff: + error_parts.extend(["Differences:", "============", git_diff]) + else: + error_parts.append("Unable to generate word diff (git not available)") + + return "\n".join(error_parts) + + def _get_git_word_diff(self, original_text, modified_text): + """Generate word diff using git with character-level precision.""" + try: + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + + # Create two files + original_file = temp_path / "original.txt" + modified_file = temp_path / "modified.txt" + + original_file.write_text(original_text, encoding="utf-8") + modified_file.write_text(modified_text, encoding="utf-8") + + # Try character-level diff first for precise differences + result = subprocess.run( + [ + "git", + "diff", + "--word-diff=plain", + "--word-diff-regex=.", # Character-by-character diff + "-U0", # Zero lines of context - show only changed lines + "--no-index", + str(original_file), + str(modified_file), + ], + capture_output=True, + text=True, + ) + + if result.stdout.strip(): + # Clean up the output - remove git diff header lines + lines = result.stdout.split("\n") + # Skip the header lines (diff --git, index, +++, ---, @@) + content_lines = [] + in_content = False + for line in lines: + if line.startswith("@@"): + in_content = True + continue + if in_content and line.strip(): + content_lines.append(line) + + if content_lines: + return "\n".join(content_lines) + + # Fallback to word-level diff if character-level is too verbose + result = subprocess.run( + [ + "git", + "diff", + "--word-diff=plain", + "-U0", # Zero lines of context + "--no-index", + str(original_file), + str(modified_file), + ], + capture_output=True, + text=True, + ) + + if result.stdout.strip(): + lines = result.stdout.split("\n") + content_lines = [] + in_content = False + for line in lines: + if line.startswith("@@"): + in_content = True + continue + if in_content and line.strip(): + content_lines.append(line) + return "\n".join(content_lines) + + except (subprocess.CalledProcessError, FileNotFoundError, Exception): + # Git not available or other error, return None to use fallback + pass + + return None + + def _remove_claude_tracked_changes(self, root): + """Remove tracked changes authored by Claude from the XML root.""" + ins_tag = f"{{{self.namespaces['w']}}}ins" + del_tag = f"{{{self.namespaces['w']}}}del" + author_attr = f"{{{self.namespaces['w']}}}author" + + # Remove w:ins elements + for parent in root.iter(): + to_remove = [] + for child in parent: + if child.tag == ins_tag and child.get(author_attr) == "Claude": + to_remove.append(child) + for elem in to_remove: + parent.remove(elem) + + # Unwrap content in w:del elements where author is "Claude" + deltext_tag = f"{{{self.namespaces['w']}}}delText" + t_tag = f"{{{self.namespaces['w']}}}t" + + for parent in root.iter(): + to_process = [] + for child in parent: + if child.tag == del_tag and child.get(author_attr) == "Claude": + to_process.append((child, list(parent).index(child))) + + # Process in reverse order to maintain indices + for del_elem, del_index in reversed(to_process): + # Convert w:delText to w:t before moving + for elem in del_elem.iter(): + if elem.tag == deltext_tag: + elem.tag = t_tag + + # Move all children of w:del to its parent before removing w:del + for child in reversed(list(del_elem)): + parent.insert(del_index, child) + parent.remove(del_elem) + + def _extract_text_content(self, root): + """Extract text content from Word XML, preserving paragraph structure. + + Empty paragraphs are skipped to avoid false positives when tracked + insertions add only structural elements without text content. + """ + p_tag = f"{{{self.namespaces['w']}}}p" + t_tag = f"{{{self.namespaces['w']}}}t" + + paragraphs = [] + for p_elem in root.findall(f".//{p_tag}"): + # Get all text elements within this paragraph + text_parts = [] + for t_elem in p_elem.findall(f".//{t_tag}"): + if t_elem.text: + text_parts.append(t_elem.text) + paragraph_text = "".join(text_parts) + # Skip empty paragraphs - they don't affect content validation + if paragraph_text: + paragraphs.append(paragraph_text) + + return "\n".join(paragraphs) + + +if __name__ == "__main__": + raise RuntimeError("This module should not be run directly.") diff --git a/skills/pptx/scripts/html2pptx.js b/skills/pptx/scripts/html2pptx.js new file mode 100755 index 0000000..437bf7c --- /dev/null +++ b/skills/pptx/scripts/html2pptx.js @@ -0,0 +1,979 @@ +/** + * html2pptx - Convert HTML slide to pptxgenjs slide with positioned elements + * + * USAGE: + * const pptx = new pptxgen(); + * pptx.layout = 'LAYOUT_16x9'; // Must match HTML body dimensions + * + * const { slide, placeholders } = await html2pptx('slide.html', pptx); + * slide.addChart(pptx.charts.LINE, data, placeholders[0]); + * + * await pptx.writeFile('output.pptx'); + * + * FEATURES: + * - Converts HTML to PowerPoint with accurate positioning + * - Supports text, images, shapes, and bullet lists + * - Extracts placeholder elements (class="placeholder") with positions + * - Handles CSS gradients, borders, and margins + * + * VALIDATION: + * - Uses body width/height from HTML for viewport sizing + * - Throws error if HTML dimensions don't match presentation layout + * - Throws error if content overflows body (with overflow details) + * + * RETURNS: + * { slide, placeholders } where placeholders is an array of { id, x, y, w, h } + */ + +const { chromium } = require('playwright'); +const path = require('path'); +const sharp = require('sharp'); + +const PT_PER_PX = 0.75; +const PX_PER_IN = 96; +const EMU_PER_IN = 914400; + +// Helper: Get body dimensions and check for overflow +async function getBodyDimensions(page) { + const bodyDimensions = await page.evaluate(() => { + const body = document.body; + const style = window.getComputedStyle(body); + + return { + width: parseFloat(style.width), + height: parseFloat(style.height), + scrollWidth: body.scrollWidth, + scrollHeight: body.scrollHeight + }; + }); + + const errors = []; + const widthOverflowPx = Math.max(0, bodyDimensions.scrollWidth - bodyDimensions.width - 1); + const heightOverflowPx = Math.max(0, bodyDimensions.scrollHeight - bodyDimensions.height - 1); + + const widthOverflowPt = widthOverflowPx * PT_PER_PX; + const heightOverflowPt = heightOverflowPx * PT_PER_PX; + + if (widthOverflowPt > 0 || heightOverflowPt > 0) { + const directions = []; + if (widthOverflowPt > 0) directions.push(`${widthOverflowPt.toFixed(1)}pt horizontally`); + if (heightOverflowPt > 0) directions.push(`${heightOverflowPt.toFixed(1)}pt vertically`); + const reminder = heightOverflowPt > 0 ? ' (Remember: leave 0.5" margin at bottom of slide)' : ''; + errors.push(`HTML content overflows body by ${directions.join(' and ')}${reminder}`); + } + + return { ...bodyDimensions, errors }; +} + +// Helper: Validate dimensions match presentation layout +function validateDimensions(bodyDimensions, pres) { + const errors = []; + const widthInches = bodyDimensions.width / PX_PER_IN; + const heightInches = bodyDimensions.height / PX_PER_IN; + + if (pres.presLayout) { + const layoutWidth = pres.presLayout.width / EMU_PER_IN; + const layoutHeight = pres.presLayout.height / EMU_PER_IN; + + if (Math.abs(layoutWidth - widthInches) > 0.1 || Math.abs(layoutHeight - heightInches) > 0.1) { + errors.push( + `HTML dimensions (${widthInches.toFixed(1)}" × ${heightInches.toFixed(1)}") ` + + `don't match presentation layout (${layoutWidth.toFixed(1)}" × ${layoutHeight.toFixed(1)}")` + ); + } + } + return errors; +} + +function validateTextBoxPosition(slideData, bodyDimensions) { + const errors = []; + const slideHeightInches = bodyDimensions.height / PX_PER_IN; + const minBottomMargin = 0.5; // 0.5 inches from bottom + + for (const el of slideData.elements) { + // Check text elements (p, h1-h6, list) + if (['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'list'].includes(el.type)) { + const fontSize = el.style?.fontSize || 0; + const bottomEdge = el.position.y + el.position.h; + const distanceFromBottom = slideHeightInches - bottomEdge; + + if (fontSize > 12 && distanceFromBottom < minBottomMargin) { + const getText = () => { + if (typeof el.text === 'string') return el.text; + if (Array.isArray(el.text)) return el.text.find(t => t.text)?.text || ''; + if (Array.isArray(el.items)) return el.items.find(item => item.text)?.text || ''; + return ''; + }; + const textPrefix = getText().substring(0, 50) + (getText().length > 50 ? '...' : ''); + + errors.push( + `Text box "${textPrefix}" ends too close to bottom edge ` + + `(${distanceFromBottom.toFixed(2)}" from bottom, minimum ${minBottomMargin}" required)` + ); + } + } + } + + return errors; +} + +// Helper: Add background to slide +async function addBackground(slideData, targetSlide, tmpDir) { + if (slideData.background.type === 'image' && slideData.background.path) { + let imagePath = slideData.background.path.startsWith('file://') + ? slideData.background.path.replace('file://', '') + : slideData.background.path; + targetSlide.background = { path: imagePath }; + } else if (slideData.background.type === 'color' && slideData.background.value) { + targetSlide.background = { color: slideData.background.value }; + } +} + +// Helper: Add elements to slide +function addElements(slideData, targetSlide, pres) { + for (const el of slideData.elements) { + if (el.type === 'image') { + let imagePath = el.src.startsWith('file://') ? el.src.replace('file://', '') : el.src; + targetSlide.addImage({ + path: imagePath, + x: el.position.x, + y: el.position.y, + w: el.position.w, + h: el.position.h + }); + } else if (el.type === 'line') { + targetSlide.addShape(pres.ShapeType.line, { + x: el.x1, + y: el.y1, + w: el.x2 - el.x1, + h: el.y2 - el.y1, + line: { color: el.color, width: el.width } + }); + } else if (el.type === 'shape') { + const shapeOptions = { + x: el.position.x, + y: el.position.y, + w: el.position.w, + h: el.position.h, + shape: el.shape.rectRadius > 0 ? pres.ShapeType.roundRect : pres.ShapeType.rect + }; + + if (el.shape.fill) { + shapeOptions.fill = { color: el.shape.fill }; + if (el.shape.transparency != null) shapeOptions.fill.transparency = el.shape.transparency; + } + if (el.shape.line) shapeOptions.line = el.shape.line; + if (el.shape.rectRadius > 0) shapeOptions.rectRadius = el.shape.rectRadius; + if (el.shape.shadow) shapeOptions.shadow = el.shape.shadow; + + targetSlide.addText(el.text || '', shapeOptions); + } else if (el.type === 'list') { + const listOptions = { + x: el.position.x, + y: el.position.y, + w: el.position.w, + h: el.position.h, + fontSize: el.style.fontSize, + fontFace: el.style.fontFace, + color: el.style.color, + align: el.style.align, + valign: 'top', + lineSpacing: el.style.lineSpacing, + paraSpaceBefore: el.style.paraSpaceBefore, + paraSpaceAfter: el.style.paraSpaceAfter, + margin: el.style.margin + }; + if (el.style.margin) listOptions.margin = el.style.margin; + targetSlide.addText(el.items, listOptions); + } else { + // Check if text is single-line (height suggests one line) + const lineHeight = el.style.lineSpacing || el.style.fontSize * 1.2; + const isSingleLine = el.position.h <= lineHeight * 1.5; + + let adjustedX = el.position.x; + let adjustedW = el.position.w; + + // Make single-line text 2% wider to account for underestimate + if (isSingleLine) { + const widthIncrease = el.position.w * 0.02; + const align = el.style.align; + + if (align === 'center') { + // Center: expand both sides + adjustedX = el.position.x - (widthIncrease / 2); + adjustedW = el.position.w + widthIncrease; + } else if (align === 'right') { + // Right: expand to the left + adjustedX = el.position.x - widthIncrease; + adjustedW = el.position.w + widthIncrease; + } else { + // Left (default): expand to the right + adjustedW = el.position.w + widthIncrease; + } + } + + const textOptions = { + x: adjustedX, + y: el.position.y, + w: adjustedW, + h: el.position.h, + fontSize: el.style.fontSize, + fontFace: el.style.fontFace, + color: el.style.color, + bold: el.style.bold, + italic: el.style.italic, + underline: el.style.underline, + valign: 'top', + lineSpacing: el.style.lineSpacing, + paraSpaceBefore: el.style.paraSpaceBefore, + paraSpaceAfter: el.style.paraSpaceAfter, + inset: 0 // Remove default PowerPoint internal padding + }; + + if (el.style.align) textOptions.align = el.style.align; + if (el.style.margin) textOptions.margin = el.style.margin; + if (el.style.rotate !== undefined) textOptions.rotate = el.style.rotate; + if (el.style.transparency !== null && el.style.transparency !== undefined) textOptions.transparency = el.style.transparency; + + targetSlide.addText(el.text, textOptions); + } + } +} + +// Helper: Extract slide data from HTML page +async function extractSlideData(page) { + return await page.evaluate(() => { + const PT_PER_PX = 0.75; + const PX_PER_IN = 96; + + // Fonts that are single-weight and should not have bold applied + // (applying bold causes PowerPoint to use faux bold which makes text wider) + const SINGLE_WEIGHT_FONTS = ['impact']; + + // Helper: Check if a font should skip bold formatting + const shouldSkipBold = (fontFamily) => { + if (!fontFamily) return false; + const normalizedFont = fontFamily.toLowerCase().replace(/['"]/g, '').split(',')[0].trim(); + return SINGLE_WEIGHT_FONTS.includes(normalizedFont); + }; + + // Unit conversion helpers + const pxToInch = (px) => px / PX_PER_IN; + const pxToPoints = (pxStr) => parseFloat(pxStr) * PT_PER_PX; + const rgbToHex = (rgbStr) => { + // Handle transparent backgrounds by defaulting to white + if (rgbStr === 'rgba(0, 0, 0, 0)' || rgbStr === 'transparent') return 'FFFFFF'; + + const match = rgbStr.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/); + if (!match) return 'FFFFFF'; + return match.slice(1).map(n => parseInt(n).toString(16).padStart(2, '0')).join(''); + }; + + const extractAlpha = (rgbStr) => { + const match = rgbStr.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\d.]+)\)/); + if (!match || !match[4]) return null; + const alpha = parseFloat(match[4]); + return Math.round((1 - alpha) * 100); + }; + + const applyTextTransform = (text, textTransform) => { + if (textTransform === 'uppercase') return text.toUpperCase(); + if (textTransform === 'lowercase') return text.toLowerCase(); + if (textTransform === 'capitalize') { + return text.replace(/\b\w/g, c => c.toUpperCase()); + } + return text; + }; + + // Extract rotation angle from CSS transform and writing-mode + const getRotation = (transform, writingMode) => { + let angle = 0; + + // Handle writing-mode first + // PowerPoint: 90° = text rotated 90° clockwise (reads top to bottom, letters upright) + // PowerPoint: 270° = text rotated 270° clockwise (reads bottom to top, letters upright) + if (writingMode === 'vertical-rl') { + // vertical-rl alone = text reads top to bottom = 90° in PowerPoint + angle = 90; + } else if (writingMode === 'vertical-lr') { + // vertical-lr alone = text reads bottom to top = 270° in PowerPoint + angle = 270; + } + + // Then add any transform rotation + if (transform && transform !== 'none') { + // Try to match rotate() function + const rotateMatch = transform.match(/rotate\((-?\d+(?:\.\d+)?)deg\)/); + if (rotateMatch) { + angle += parseFloat(rotateMatch[1]); + } else { + // Browser may compute as matrix - extract rotation from matrix + const matrixMatch = transform.match(/matrix\(([^)]+)\)/); + if (matrixMatch) { + const values = matrixMatch[1].split(',').map(parseFloat); + // matrix(a, b, c, d, e, f) where rotation = atan2(b, a) + const matrixAngle = Math.atan2(values[1], values[0]) * (180 / Math.PI); + angle += Math.round(matrixAngle); + } + } + } + + // Normalize to 0-359 range + angle = angle % 360; + if (angle < 0) angle += 360; + + return angle === 0 ? null : angle; + }; + + // Get position/dimensions accounting for rotation + const getPositionAndSize = (el, rect, rotation) => { + if (rotation === null) { + return { x: rect.left, y: rect.top, w: rect.width, h: rect.height }; + } + + // For 90° or 270° rotations, swap width and height + // because PowerPoint applies rotation to the original (unrotated) box + const isVertical = rotation === 90 || rotation === 270; + + if (isVertical) { + // The browser shows us the rotated dimensions (tall box for vertical text) + // But PowerPoint needs the pre-rotation dimensions (wide box that will be rotated) + // So we swap: browser's height becomes PPT's width, browser's width becomes PPT's height + const centerX = rect.left + rect.width / 2; + const centerY = rect.top + rect.height / 2; + + return { + x: centerX - rect.height / 2, + y: centerY - rect.width / 2, + w: rect.height, + h: rect.width + }; + } + + // For other rotations, use element's offset dimensions + const centerX = rect.left + rect.width / 2; + const centerY = rect.top + rect.height / 2; + return { + x: centerX - el.offsetWidth / 2, + y: centerY - el.offsetHeight / 2, + w: el.offsetWidth, + h: el.offsetHeight + }; + }; + + // Parse CSS box-shadow into PptxGenJS shadow properties + const parseBoxShadow = (boxShadow) => { + if (!boxShadow || boxShadow === 'none') return null; + + // Browser computed style format: "rgba(0, 0, 0, 0.3) 2px 2px 8px 0px [inset]" + // CSS format: "[inset] 2px 2px 8px 0px rgba(0, 0, 0, 0.3)" + + const insetMatch = boxShadow.match(/inset/); + + // IMPORTANT: PptxGenJS/PowerPoint doesn't properly support inset shadows + // Only process outer shadows to avoid file corruption + if (insetMatch) return null; + + // Extract color first (rgba or rgb at start) + const colorMatch = boxShadow.match(/rgba?\([^)]+\)/); + + // Extract numeric values (handles both px and pt units) + const parts = boxShadow.match(/([-\d.]+)(px|pt)/g); + + if (!parts || parts.length < 2) return null; + + const offsetX = parseFloat(parts[0]); + const offsetY = parseFloat(parts[1]); + const blur = parts.length > 2 ? parseFloat(parts[2]) : 0; + + // Calculate angle from offsets (in degrees, 0 = right, 90 = down) + let angle = 0; + if (offsetX !== 0 || offsetY !== 0) { + angle = Math.atan2(offsetY, offsetX) * (180 / Math.PI); + if (angle < 0) angle += 360; + } + + // Calculate offset distance (hypotenuse) + const offset = Math.sqrt(offsetX * offsetX + offsetY * offsetY) * PT_PER_PX; + + // Extract opacity from rgba + let opacity = 0.5; + if (colorMatch) { + const opacityMatch = colorMatch[0].match(/[\d.]+\)$/); + if (opacityMatch) { + opacity = parseFloat(opacityMatch[0].replace(')', '')); + } + } + + return { + type: 'outer', + angle: Math.round(angle), + blur: blur * 0.75, // Convert to points + color: colorMatch ? rgbToHex(colorMatch[0]) : '000000', + offset: offset, + opacity + }; + }; + + // Parse inline formatting tags (<b>, <i>, <u>, <strong>, <em>, <span>) into text runs + const parseInlineFormatting = (element, baseOptions = {}, runs = [], baseTextTransform = (x) => x) => { + let prevNodeIsText = false; + + element.childNodes.forEach((node) => { + let textTransform = baseTextTransform; + + const isText = node.nodeType === Node.TEXT_NODE || node.tagName === 'BR'; + if (isText) { + const text = node.tagName === 'BR' ? '\n' : textTransform(node.textContent.replace(/\s+/g, ' ')); + const prevRun = runs[runs.length - 1]; + if (prevNodeIsText && prevRun) { + prevRun.text += text; + } else { + runs.push({ text, options: { ...baseOptions } }); + } + + } else if (node.nodeType === Node.ELEMENT_NODE && node.textContent.trim()) { + const options = { ...baseOptions }; + const computed = window.getComputedStyle(node); + + // Handle inline elements with computed styles + if (node.tagName === 'SPAN' || node.tagName === 'B' || node.tagName === 'STRONG' || node.tagName === 'I' || node.tagName === 'EM' || node.tagName === 'U') { + const isBold = computed.fontWeight === 'bold' || parseInt(computed.fontWeight) >= 600; + if (isBold && !shouldSkipBold(computed.fontFamily)) options.bold = true; + if (computed.fontStyle === 'italic') options.italic = true; + if (computed.textDecoration && computed.textDecoration.includes('underline')) options.underline = true; + if (computed.color && computed.color !== 'rgb(0, 0, 0)') { + options.color = rgbToHex(computed.color); + const transparency = extractAlpha(computed.color); + if (transparency !== null) options.transparency = transparency; + } + if (computed.fontSize) options.fontSize = pxToPoints(computed.fontSize); + + // Apply text-transform on the span element itself + if (computed.textTransform && computed.textTransform !== 'none') { + const transformStr = computed.textTransform; + textTransform = (text) => applyTextTransform(text, transformStr); + } + + // Validate: Check for margins on inline elements + if (computed.marginLeft && parseFloat(computed.marginLeft) > 0) { + errors.push(`Inline element <${node.tagName.toLowerCase()}> has margin-left which is not supported in PowerPoint. Remove margin from inline elements.`); + } + if (computed.marginRight && parseFloat(computed.marginRight) > 0) { + errors.push(`Inline element <${node.tagName.toLowerCase()}> has margin-right which is not supported in PowerPoint. Remove margin from inline elements.`); + } + if (computed.marginTop && parseFloat(computed.marginTop) > 0) { + errors.push(`Inline element <${node.tagName.toLowerCase()}> has margin-top which is not supported in PowerPoint. Remove margin from inline elements.`); + } + if (computed.marginBottom && parseFloat(computed.marginBottom) > 0) { + errors.push(`Inline element <${node.tagName.toLowerCase()}> has margin-bottom which is not supported in PowerPoint. Remove margin from inline elements.`); + } + + // Recursively process the child node. This will flatten nested spans into multiple runs. + parseInlineFormatting(node, options, runs, textTransform); + } + } + + prevNodeIsText = isText; + }); + + // Trim leading space from first run and trailing space from last run + if (runs.length > 0) { + runs[0].text = runs[0].text.replace(/^\s+/, ''); + runs[runs.length - 1].text = runs[runs.length - 1].text.replace(/\s+$/, ''); + } + + return runs.filter(r => r.text.length > 0); + }; + + // Extract background from body (image or color) + const body = document.body; + const bodyStyle = window.getComputedStyle(body); + const bgImage = bodyStyle.backgroundImage; + const bgColor = bodyStyle.backgroundColor; + + // Collect validation errors + const errors = []; + + // Validate: Check for CSS gradients + if (bgImage && (bgImage.includes('linear-gradient') || bgImage.includes('radial-gradient'))) { + errors.push( + 'CSS gradients are not supported. Use Sharp to rasterize gradients as PNG images first, ' + + 'then reference with background-image: url(\'gradient.png\')' + ); + } + + let background; + if (bgImage && bgImage !== 'none') { + // Extract URL from url("...") or url(...) + const urlMatch = bgImage.match(/url\(["']?([^"')]+)["']?\)/); + if (urlMatch) { + background = { + type: 'image', + path: urlMatch[1] + }; + } else { + background = { + type: 'color', + value: rgbToHex(bgColor) + }; + } + } else { + background = { + type: 'color', + value: rgbToHex(bgColor) + }; + } + + // Process all elements + const elements = []; + const placeholders = []; + const textTags = ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'UL', 'OL', 'LI']; + const processed = new Set(); + + document.querySelectorAll('*').forEach((el) => { + if (processed.has(el)) return; + + // Validate text elements don't have backgrounds, borders, or shadows + if (textTags.includes(el.tagName)) { + const computed = window.getComputedStyle(el); + const hasBg = computed.backgroundColor && computed.backgroundColor !== 'rgba(0, 0, 0, 0)'; + const hasBorder = (computed.borderWidth && parseFloat(computed.borderWidth) > 0) || + (computed.borderTopWidth && parseFloat(computed.borderTopWidth) > 0) || + (computed.borderRightWidth && parseFloat(computed.borderRightWidth) > 0) || + (computed.borderBottomWidth && parseFloat(computed.borderBottomWidth) > 0) || + (computed.borderLeftWidth && parseFloat(computed.borderLeftWidth) > 0); + const hasShadow = computed.boxShadow && computed.boxShadow !== 'none'; + + if (hasBg || hasBorder || hasShadow) { + errors.push( + `Text element <${el.tagName.toLowerCase()}> has ${hasBg ? 'background' : hasBorder ? 'border' : 'shadow'}. ` + + 'Backgrounds, borders, and shadows are only supported on <div> elements, not text elements.' + ); + return; + } + } + + // Extract placeholder elements (for charts, etc.) + if (el.className && el.className.includes('placeholder')) { + const rect = el.getBoundingClientRect(); + if (rect.width === 0 || rect.height === 0) { + errors.push( + `Placeholder "${el.id || 'unnamed'}" has ${rect.width === 0 ? 'width: 0' : 'height: 0'}. Check the layout CSS.` + ); + } else { + placeholders.push({ + id: el.id || `placeholder-${placeholders.length}`, + x: pxToInch(rect.left), + y: pxToInch(rect.top), + w: pxToInch(rect.width), + h: pxToInch(rect.height) + }); + } + processed.add(el); + return; + } + + // Extract images + if (el.tagName === 'IMG') { + const rect = el.getBoundingClientRect(); + if (rect.width > 0 && rect.height > 0) { + elements.push({ + type: 'image', + src: el.src, + position: { + x: pxToInch(rect.left), + y: pxToInch(rect.top), + w: pxToInch(rect.width), + h: pxToInch(rect.height) + } + }); + processed.add(el); + return; + } + } + + // Extract DIVs with backgrounds/borders as shapes + const isContainer = el.tagName === 'DIV' && !textTags.includes(el.tagName); + if (isContainer) { + const computed = window.getComputedStyle(el); + const hasBg = computed.backgroundColor && computed.backgroundColor !== 'rgba(0, 0, 0, 0)'; + + // Validate: Check for unwrapped text content in DIV + for (const node of el.childNodes) { + if (node.nodeType === Node.TEXT_NODE) { + const text = node.textContent.trim(); + if (text) { + errors.push( + `DIV element contains unwrapped text "${text.substring(0, 50)}${text.length > 50 ? '...' : ''}". ` + + 'All text must be wrapped in <p>, <h1>-<h6>, <ul>, or <ol> tags to appear in PowerPoint.' + ); + } + } + } + + // Check for background images on shapes + const bgImage = computed.backgroundImage; + if (bgImage && bgImage !== 'none') { + errors.push( + 'Background images on DIV elements are not supported. ' + + 'Use solid colors or borders for shapes, or use slide.addImage() in PptxGenJS to layer images.' + ); + return; + } + + // Check for borders - both uniform and partial + const borderTop = computed.borderTopWidth; + const borderRight = computed.borderRightWidth; + const borderBottom = computed.borderBottomWidth; + const borderLeft = computed.borderLeftWidth; + const borders = [borderTop, borderRight, borderBottom, borderLeft].map(b => parseFloat(b) || 0); + const hasBorder = borders.some(b => b > 0); + const hasUniformBorder = hasBorder && borders.every(b => b === borders[0]); + const borderLines = []; + + if (hasBorder && !hasUniformBorder) { + const rect = el.getBoundingClientRect(); + const x = pxToInch(rect.left); + const y = pxToInch(rect.top); + const w = pxToInch(rect.width); + const h = pxToInch(rect.height); + + // Collect lines to add after shape (inset by half the line width to center on edge) + if (parseFloat(borderTop) > 0) { + const widthPt = pxToPoints(borderTop); + const inset = (widthPt / 72) / 2; // Convert points to inches, then half + borderLines.push({ + type: 'line', + x1: x, y1: y + inset, x2: x + w, y2: y + inset, + width: widthPt, + color: rgbToHex(computed.borderTopColor) + }); + } + if (parseFloat(borderRight) > 0) { + const widthPt = pxToPoints(borderRight); + const inset = (widthPt / 72) / 2; + borderLines.push({ + type: 'line', + x1: x + w - inset, y1: y, x2: x + w - inset, y2: y + h, + width: widthPt, + color: rgbToHex(computed.borderRightColor) + }); + } + if (parseFloat(borderBottom) > 0) { + const widthPt = pxToPoints(borderBottom); + const inset = (widthPt / 72) / 2; + borderLines.push({ + type: 'line', + x1: x, y1: y + h - inset, x2: x + w, y2: y + h - inset, + width: widthPt, + color: rgbToHex(computed.borderBottomColor) + }); + } + if (parseFloat(borderLeft) > 0) { + const widthPt = pxToPoints(borderLeft); + const inset = (widthPt / 72) / 2; + borderLines.push({ + type: 'line', + x1: x + inset, y1: y, x2: x + inset, y2: y + h, + width: widthPt, + color: rgbToHex(computed.borderLeftColor) + }); + } + } + + if (hasBg || hasBorder) { + const rect = el.getBoundingClientRect(); + if (rect.width > 0 && rect.height > 0) { + const shadow = parseBoxShadow(computed.boxShadow); + + // Only add shape if there's background or uniform border + if (hasBg || hasUniformBorder) { + elements.push({ + type: 'shape', + text: '', // Shape only - child text elements render on top + position: { + x: pxToInch(rect.left), + y: pxToInch(rect.top), + w: pxToInch(rect.width), + h: pxToInch(rect.height) + }, + shape: { + fill: hasBg ? rgbToHex(computed.backgroundColor) : null, + transparency: hasBg ? extractAlpha(computed.backgroundColor) : null, + line: hasUniformBorder ? { + color: rgbToHex(computed.borderColor), + width: pxToPoints(computed.borderWidth) + } : null, + // Convert border-radius to rectRadius (in inches) + // % values: 50%+ = circle (1), <50% = percentage of min dimension + // pt values: divide by 72 (72pt = 1 inch) + // px values: divide by 96 (96px = 1 inch) + rectRadius: (() => { + const radius = computed.borderRadius; + const radiusValue = parseFloat(radius); + if (radiusValue === 0) return 0; + + if (radius.includes('%')) { + if (radiusValue >= 50) return 1; + // Calculate percentage of smaller dimension + const minDim = Math.min(rect.width, rect.height); + return (radiusValue / 100) * pxToInch(minDim); + } + + if (radius.includes('pt')) return radiusValue / 72; + return radiusValue / PX_PER_IN; + })(), + shadow: shadow + } + }); + } + + // Add partial border lines + elements.push(...borderLines); + + processed.add(el); + return; + } + } + } + + // Extract bullet lists as single text block + if (el.tagName === 'UL' || el.tagName === 'OL') { + const rect = el.getBoundingClientRect(); + if (rect.width === 0 || rect.height === 0) return; + + const liElements = Array.from(el.querySelectorAll('li')); + const items = []; + const ulComputed = window.getComputedStyle(el); + const ulPaddingLeftPt = pxToPoints(ulComputed.paddingLeft); + + // Split: margin-left for bullet position, indent for text position + // margin-left + indent = ul padding-left + const marginLeft = ulPaddingLeftPt * 0.5; + const textIndent = ulPaddingLeftPt * 0.5; + + liElements.forEach((li, idx) => { + const isLast = idx === liElements.length - 1; + const runs = parseInlineFormatting(li, { breakLine: false }); + // Clean manual bullets from first run + if (runs.length > 0) { + runs[0].text = runs[0].text.replace(/^[•\-\*▪▸]\s*/, ''); + runs[0].options.bullet = { indent: textIndent }; + } + // Set breakLine on last run + if (runs.length > 0 && !isLast) { + runs[runs.length - 1].options.breakLine = true; + } + items.push(...runs); + }); + + const computed = window.getComputedStyle(liElements[0] || el); + + elements.push({ + type: 'list', + items: items, + position: { + x: pxToInch(rect.left), + y: pxToInch(rect.top), + w: pxToInch(rect.width), + h: pxToInch(rect.height) + }, + style: { + fontSize: pxToPoints(computed.fontSize), + fontFace: computed.fontFamily.split(',')[0].replace(/['"]/g, '').trim(), + color: rgbToHex(computed.color), + transparency: extractAlpha(computed.color), + align: computed.textAlign === 'start' ? 'left' : computed.textAlign, + lineSpacing: computed.lineHeight && computed.lineHeight !== 'normal' ? pxToPoints(computed.lineHeight) : null, + paraSpaceBefore: 0, + paraSpaceAfter: pxToPoints(computed.marginBottom), + // PptxGenJS margin array is [left, right, bottom, top] + margin: [marginLeft, 0, 0, 0] + } + }); + + liElements.forEach(li => processed.add(li)); + processed.add(el); + return; + } + + // Extract text elements (P, H1, H2, etc.) + if (!textTags.includes(el.tagName)) return; + + const rect = el.getBoundingClientRect(); + const text = el.textContent.trim(); + if (rect.width === 0 || rect.height === 0 || !text) return; + + // Validate: Check for manual bullet symbols in text elements (not in lists) + if (el.tagName !== 'LI' && /^[•\-\*▪▸○●◆◇■□]\s/.test(text.trimStart())) { + errors.push( + `Text element <${el.tagName.toLowerCase()}> starts with bullet symbol "${text.substring(0, 20)}...". ` + + 'Use <ul> or <ol> lists instead of manual bullet symbols.' + ); + return; + } + + const computed = window.getComputedStyle(el); + const rotation = getRotation(computed.transform, computed.writingMode); + const { x, y, w, h } = getPositionAndSize(el, rect, rotation); + + const baseStyle = { + fontSize: pxToPoints(computed.fontSize), + fontFace: computed.fontFamily.split(',')[0].replace(/['"]/g, '').trim(), + color: rgbToHex(computed.color), + align: computed.textAlign === 'start' ? 'left' : computed.textAlign, + lineSpacing: pxToPoints(computed.lineHeight), + paraSpaceBefore: pxToPoints(computed.marginTop), + paraSpaceAfter: pxToPoints(computed.marginBottom), + // PptxGenJS margin array is [left, right, bottom, top] (not [top, right, bottom, left] as documented) + margin: [ + pxToPoints(computed.paddingLeft), + pxToPoints(computed.paddingRight), + pxToPoints(computed.paddingBottom), + pxToPoints(computed.paddingTop) + ] + }; + + const transparency = extractAlpha(computed.color); + if (transparency !== null) baseStyle.transparency = transparency; + + if (rotation !== null) baseStyle.rotate = rotation; + + const hasFormatting = el.querySelector('b, i, u, strong, em, span, br'); + + if (hasFormatting) { + // Text with inline formatting + const transformStr = computed.textTransform; + const runs = parseInlineFormatting(el, {}, [], (str) => applyTextTransform(str, transformStr)); + + // Adjust lineSpacing based on largest fontSize in runs + const adjustedStyle = { ...baseStyle }; + if (adjustedStyle.lineSpacing) { + const maxFontSize = Math.max( + adjustedStyle.fontSize, + ...runs.map(r => r.options?.fontSize || 0) + ); + if (maxFontSize > adjustedStyle.fontSize) { + const lineHeightMultiplier = adjustedStyle.lineSpacing / adjustedStyle.fontSize; + adjustedStyle.lineSpacing = maxFontSize * lineHeightMultiplier; + } + } + + elements.push({ + type: el.tagName.toLowerCase(), + text: runs, + position: { x: pxToInch(x), y: pxToInch(y), w: pxToInch(w), h: pxToInch(h) }, + style: adjustedStyle + }); + } else { + // Plain text - inherit CSS formatting + const textTransform = computed.textTransform; + const transformedText = applyTextTransform(text, textTransform); + + const isBold = computed.fontWeight === 'bold' || parseInt(computed.fontWeight) >= 600; + + elements.push({ + type: el.tagName.toLowerCase(), + text: transformedText, + position: { x: pxToInch(x), y: pxToInch(y), w: pxToInch(w), h: pxToInch(h) }, + style: { + ...baseStyle, + bold: isBold && !shouldSkipBold(computed.fontFamily), + italic: computed.fontStyle === 'italic', + underline: computed.textDecoration.includes('underline') + } + }); + } + + processed.add(el); + }); + + return { background, elements, placeholders, errors }; + }); +} + +async function html2pptx(htmlFile, pres, options = {}) { + const { + tmpDir = process.env.TMPDIR || '/tmp', + slide = null + } = options; + + try { + // Use Chrome on macOS, default Chromium on Unix + const launchOptions = { env: { TMPDIR: tmpDir } }; + if (process.platform === 'darwin') { + launchOptions.channel = 'chrome'; + } + + const browser = await chromium.launch(launchOptions); + + let bodyDimensions; + let slideData; + + const filePath = path.isAbsolute(htmlFile) ? htmlFile : path.join(process.cwd(), htmlFile); + const validationErrors = []; + + try { + const page = await browser.newPage(); + page.on('console', (msg) => { + // Log the message text to your test runner's console + console.log(`Browser console: ${msg.text()}`); + }); + + await page.goto(`file://${filePath}`); + + bodyDimensions = await getBodyDimensions(page); + + await page.setViewportSize({ + width: Math.round(bodyDimensions.width), + height: Math.round(bodyDimensions.height) + }); + + slideData = await extractSlideData(page); + } finally { + await browser.close(); + } + + // Collect all validation errors + if (bodyDimensions.errors && bodyDimensions.errors.length > 0) { + validationErrors.push(...bodyDimensions.errors); + } + + const dimensionErrors = validateDimensions(bodyDimensions, pres); + if (dimensionErrors.length > 0) { + validationErrors.push(...dimensionErrors); + } + + const textBoxPositionErrors = validateTextBoxPosition(slideData, bodyDimensions); + if (textBoxPositionErrors.length > 0) { + validationErrors.push(...textBoxPositionErrors); + } + + if (slideData.errors && slideData.errors.length > 0) { + validationErrors.push(...slideData.errors); + } + + // Throw all errors at once if any exist + if (validationErrors.length > 0) { + const errorMessage = validationErrors.length === 1 + ? validationErrors[0] + : `Multiple validation errors found:\n${validationErrors.map((e, i) => ` ${i + 1}. ${e}`).join('\n')}`; + throw new Error(errorMessage); + } + + const targetSlide = slide || pres.addSlide(); + + await addBackground(slideData, targetSlide, tmpDir); + addElements(slideData, targetSlide, pres); + + return { slide: targetSlide, placeholders: slideData.placeholders }; + } catch (error) { + if (!error.message.startsWith(htmlFile)) { + throw new Error(`${htmlFile}: ${error.message}`); + } + throw error; + } +} + +module.exports = html2pptx; \ No newline at end of file diff --git a/skills/pptx/scripts/inventory.py b/skills/pptx/scripts/inventory.py new file mode 100755 index 0000000..edda390 --- /dev/null +++ b/skills/pptx/scripts/inventory.py @@ -0,0 +1,1020 @@ +#!/usr/bin/env python3 +""" +Extract structured text content from PowerPoint presentations. + +This module provides functionality to: +- Extract all text content from PowerPoint shapes +- Preserve paragraph formatting (alignment, bullets, fonts, spacing) +- Handle nested GroupShapes recursively with correct absolute positions +- Sort shapes by visual position on slides +- Filter out slide numbers and non-content placeholders +- Export to JSON with clean, structured data + +Classes: + ParagraphData: Represents a text paragraph with formatting + ShapeData: Represents a shape with position and text content + +Main Functions: + extract_text_inventory: Extract all text from a presentation + save_inventory: Save extracted data to JSON + +Usage: + python inventory.py input.pptx output.json +""" + +import argparse +import json +import platform +import sys +from dataclasses import dataclass +from pathlib import Path +from typing import Any, Dict, List, Optional, Tuple, Union + +from PIL import Image, ImageDraw, ImageFont +from pptx import Presentation +from pptx.enum.text import PP_ALIGN +from pptx.shapes.base import BaseShape + +# Type aliases for cleaner signatures +JsonValue = Union[str, int, float, bool, None] +ParagraphDict = Dict[str, JsonValue] +ShapeDict = Dict[ + str, Union[str, float, bool, List[ParagraphDict], List[str], Dict[str, Any], None] +] +InventoryData = Dict[ + str, Dict[str, "ShapeData"] +] # Dict of slide_id -> {shape_id -> ShapeData} +InventoryDict = Dict[str, Dict[str, ShapeDict]] # JSON-serializable inventory + + +def main(): + """Main entry point for command-line usage.""" + parser = argparse.ArgumentParser( + description="Extract text inventory from PowerPoint with proper GroupShape support.", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + python inventory.py presentation.pptx inventory.json + Extracts text inventory with correct absolute positions for grouped shapes + + python inventory.py presentation.pptx inventory.json --issues-only + Extracts only text shapes that have overflow or overlap issues + +The output JSON includes: + - All text content organized by slide and shape + - Correct absolute positions for shapes in groups + - Visual position and size in inches + - Paragraph properties and formatting + - Issue detection: text overflow and shape overlaps + """, + ) + + parser.add_argument("input", help="Input PowerPoint file (.pptx)") + parser.add_argument("output", help="Output JSON file for inventory") + parser.add_argument( + "--issues-only", + action="store_true", + help="Include only text shapes that have overflow or overlap issues", + ) + + args = parser.parse_args() + + input_path = Path(args.input) + if not input_path.exists(): + print(f"Error: Input file not found: {args.input}") + sys.exit(1) + + if not input_path.suffix.lower() == ".pptx": + print("Error: Input must be a PowerPoint file (.pptx)") + sys.exit(1) + + try: + print(f"Extracting text inventory from: {args.input}") + if args.issues_only: + print( + "Filtering to include only text shapes with issues (overflow/overlap)" + ) + inventory = extract_text_inventory(input_path, issues_only=args.issues_only) + + output_path = Path(args.output) + output_path.parent.mkdir(parents=True, exist_ok=True) + save_inventory(inventory, output_path) + + print(f"Output saved to: {args.output}") + + # Report statistics + total_slides = len(inventory) + total_shapes = sum(len(shapes) for shapes in inventory.values()) + if args.issues_only: + if total_shapes > 0: + print( + f"Found {total_shapes} text elements with issues in {total_slides} slides" + ) + else: + print("No issues discovered") + else: + print( + f"Found text in {total_slides} slides with {total_shapes} text elements" + ) + + except Exception as e: + print(f"Error processing presentation: {e}") + import traceback + + traceback.print_exc() + sys.exit(1) + + +@dataclass +class ShapeWithPosition: + """A shape with its absolute position on the slide.""" + + shape: BaseShape + absolute_left: int # in EMUs + absolute_top: int # in EMUs + + +class ParagraphData: + """Data structure for paragraph properties extracted from a PowerPoint paragraph.""" + + def __init__(self, paragraph: Any): + """Initialize from a PowerPoint paragraph object. + + Args: + paragraph: The PowerPoint paragraph object + """ + self.text: str = paragraph.text.strip() + self.bullet: bool = False + self.level: Optional[int] = None + self.alignment: Optional[str] = None + self.space_before: Optional[float] = None + self.space_after: Optional[float] = None + self.font_name: Optional[str] = None + self.font_size: Optional[float] = None + self.bold: Optional[bool] = None + self.italic: Optional[bool] = None + self.underline: Optional[bool] = None + self.color: Optional[str] = None + self.theme_color: Optional[str] = None + self.line_spacing: Optional[float] = None + + # Check for bullet formatting + if ( + hasattr(paragraph, "_p") + and paragraph._p is not None + and paragraph._p.pPr is not None + ): + pPr = paragraph._p.pPr + ns = "{http://schemas.openxmlformats.org/drawingml/2006/main}" + if ( + pPr.find(f"{ns}buChar") is not None + or pPr.find(f"{ns}buAutoNum") is not None + ): + self.bullet = True + if hasattr(paragraph, "level"): + self.level = paragraph.level + + # Add alignment if not LEFT (default) + if hasattr(paragraph, "alignment") and paragraph.alignment is not None: + alignment_map = { + PP_ALIGN.CENTER: "CENTER", + PP_ALIGN.RIGHT: "RIGHT", + PP_ALIGN.JUSTIFY: "JUSTIFY", + } + if paragraph.alignment in alignment_map: + self.alignment = alignment_map[paragraph.alignment] + + # Add spacing properties if set + if hasattr(paragraph, "space_before") and paragraph.space_before: + self.space_before = paragraph.space_before.pt + if hasattr(paragraph, "space_after") and paragraph.space_after: + self.space_after = paragraph.space_after.pt + + # Extract font properties from first run + if paragraph.runs: + first_run = paragraph.runs[0] + if hasattr(first_run, "font"): + font = first_run.font + if font.name: + self.font_name = font.name + if font.size: + self.font_size = font.size.pt + if font.bold is not None: + self.bold = font.bold + if font.italic is not None: + self.italic = font.italic + if font.underline is not None: + self.underline = font.underline + + # Handle color - both RGB and theme colors + try: + # Try RGB color first + if font.color.rgb: + self.color = str(font.color.rgb) + except (AttributeError, TypeError): + # Fall back to theme color + try: + if font.color.theme_color: + self.theme_color = font.color.theme_color.name + except (AttributeError, TypeError): + pass + + # Add line spacing if set + if hasattr(paragraph, "line_spacing") and paragraph.line_spacing is not None: + if hasattr(paragraph.line_spacing, "pt"): + self.line_spacing = round(paragraph.line_spacing.pt, 2) + else: + # Multiplier - convert to points + font_size = self.font_size if self.font_size else 12.0 + self.line_spacing = round(paragraph.line_spacing * font_size, 2) + + def to_dict(self) -> ParagraphDict: + """Convert to dictionary for JSON serialization, excluding None values.""" + result: ParagraphDict = {"text": self.text} + + # Add optional fields only if they have values + if self.bullet: + result["bullet"] = self.bullet + if self.level is not None: + result["level"] = self.level + if self.alignment: + result["alignment"] = self.alignment + if self.space_before is not None: + result["space_before"] = self.space_before + if self.space_after is not None: + result["space_after"] = self.space_after + if self.font_name: + result["font_name"] = self.font_name + if self.font_size is not None: + result["font_size"] = self.font_size + if self.bold is not None: + result["bold"] = self.bold + if self.italic is not None: + result["italic"] = self.italic + if self.underline is not None: + result["underline"] = self.underline + if self.color: + result["color"] = self.color + if self.theme_color: + result["theme_color"] = self.theme_color + if self.line_spacing is not None: + result["line_spacing"] = self.line_spacing + + return result + + +class ShapeData: + """Data structure for shape properties extracted from a PowerPoint shape.""" + + @staticmethod + def emu_to_inches(emu: int) -> float: + """Convert EMUs (English Metric Units) to inches.""" + return emu / 914400.0 + + @staticmethod + def inches_to_pixels(inches: float, dpi: int = 96) -> int: + """Convert inches to pixels at given DPI.""" + return int(inches * dpi) + + @staticmethod + def get_font_path(font_name: str) -> Optional[str]: + """Get the font file path for a given font name. + + Args: + font_name: Name of the font (e.g., 'Arial', 'Calibri') + + Returns: + Path to the font file, or None if not found + """ + system = platform.system() + + # Common font file variations to try + font_variations = [ + font_name, + font_name.lower(), + font_name.replace(" ", ""), + font_name.replace(" ", "-"), + ] + + # Define font directories and extensions by platform + if system == "Darwin": # macOS + font_dirs = [ + "/System/Library/Fonts/", + "/Library/Fonts/", + "~/Library/Fonts/", + ] + extensions = [".ttf", ".otf", ".ttc", ".dfont"] + else: # Linux + font_dirs = [ + "/usr/share/fonts/truetype/", + "/usr/local/share/fonts/", + "~/.fonts/", + ] + extensions = [".ttf", ".otf"] + + # Try to find the font file + from pathlib import Path + + for font_dir in font_dirs: + font_dir_path = Path(font_dir).expanduser() + if not font_dir_path.exists(): + continue + + # First try exact matches + for variant in font_variations: + for ext in extensions: + font_path = font_dir_path / f"{variant}{ext}" + if font_path.exists(): + return str(font_path) + + # Then try fuzzy matching - find files containing the font name + try: + for file_path in font_dir_path.iterdir(): + if file_path.is_file(): + file_name_lower = file_path.name.lower() + font_name_lower = font_name.lower().replace(" ", "") + if font_name_lower in file_name_lower and any( + file_name_lower.endswith(ext) for ext in extensions + ): + return str(file_path) + except (OSError, PermissionError): + continue + + return None + + @staticmethod + def get_slide_dimensions(slide: Any) -> tuple[Optional[int], Optional[int]]: + """Get slide dimensions from slide object. + + Args: + slide: Slide object + + Returns: + Tuple of (width_emu, height_emu) or (None, None) if not found + """ + try: + prs = slide.part.package.presentation_part.presentation + return prs.slide_width, prs.slide_height + except (AttributeError, TypeError): + return None, None + + @staticmethod + def get_default_font_size(shape: BaseShape, slide_layout: Any) -> Optional[float]: + """Extract default font size from slide layout for a placeholder shape. + + Args: + shape: Placeholder shape + slide_layout: Slide layout containing the placeholder definition + + Returns: + Default font size in points, or None if not found + """ + try: + if not hasattr(shape, "placeholder_format"): + return None + + shape_type = shape.placeholder_format.type # type: ignore + for layout_placeholder in slide_layout.placeholders: + if layout_placeholder.placeholder_format.type == shape_type: + # Find first defRPr element with sz (size) attribute + for elem in layout_placeholder.element.iter(): + if "defRPr" in elem.tag and (sz := elem.get("sz")): + return float(sz) / 100.0 # Convert EMUs to points + break + except Exception: + pass + return None + + def __init__( + self, + shape: BaseShape, + absolute_left: Optional[int] = None, + absolute_top: Optional[int] = None, + slide: Optional[Any] = None, + ): + """Initialize from a PowerPoint shape object. + + Args: + shape: The PowerPoint shape object (should be pre-validated) + absolute_left: Absolute left position in EMUs (for shapes in groups) + absolute_top: Absolute top position in EMUs (for shapes in groups) + slide: Optional slide object to get dimensions and layout information + """ + self.shape = shape # Store reference to original shape + self.shape_id: str = "" # Will be set after sorting + + # Get slide dimensions from slide object + self.slide_width_emu, self.slide_height_emu = ( + self.get_slide_dimensions(slide) if slide else (None, None) + ) + + # Get placeholder type if applicable + self.placeholder_type: Optional[str] = None + self.default_font_size: Optional[float] = None + if hasattr(shape, "is_placeholder") and shape.is_placeholder: # type: ignore + if shape.placeholder_format and shape.placeholder_format.type: # type: ignore + self.placeholder_type = ( + str(shape.placeholder_format.type).split(".")[-1].split(" ")[0] # type: ignore + ) + + # Get default font size from layout + if slide and hasattr(slide, "slide_layout"): + self.default_font_size = self.get_default_font_size( + shape, slide.slide_layout + ) + + # Get position information + # Use absolute positions if provided (for shapes in groups), otherwise use shape's position + left_emu = ( + absolute_left + if absolute_left is not None + else (shape.left if hasattr(shape, "left") else 0) + ) + top_emu = ( + absolute_top + if absolute_top is not None + else (shape.top if hasattr(shape, "top") else 0) + ) + + self.left: float = round(self.emu_to_inches(left_emu), 2) # type: ignore + self.top: float = round(self.emu_to_inches(top_emu), 2) # type: ignore + self.width: float = round( + self.emu_to_inches(shape.width if hasattr(shape, "width") else 0), + 2, # type: ignore + ) + self.height: float = round( + self.emu_to_inches(shape.height if hasattr(shape, "height") else 0), + 2, # type: ignore + ) + + # Store EMU positions for overflow calculations + self.left_emu = left_emu + self.top_emu = top_emu + self.width_emu = shape.width if hasattr(shape, "width") else 0 + self.height_emu = shape.height if hasattr(shape, "height") else 0 + + # Calculate overflow status + self.frame_overflow_bottom: Optional[float] = None + self.slide_overflow_right: Optional[float] = None + self.slide_overflow_bottom: Optional[float] = None + self.overlapping_shapes: Dict[ + str, float + ] = {} # Dict of shape_id -> overlap area in sq inches + self.warnings: List[str] = [] + self._estimate_frame_overflow() + self._calculate_slide_overflow() + self._detect_bullet_issues() + + @property + def paragraphs(self) -> List[ParagraphData]: + """Calculate paragraphs from the shape's text frame.""" + if not self.shape or not hasattr(self.shape, "text_frame"): + return [] + + paragraphs = [] + for paragraph in self.shape.text_frame.paragraphs: # type: ignore + if paragraph.text.strip(): + paragraphs.append(ParagraphData(paragraph)) + return paragraphs + + def _get_default_font_size(self) -> int: + """Get default font size from theme text styles or use conservative default.""" + try: + if not ( + hasattr(self.shape, "part") and hasattr(self.shape.part, "slide_layout") + ): + return 14 + + slide_master = self.shape.part.slide_layout.slide_master # type: ignore + if not hasattr(slide_master, "element"): + return 14 + + # Determine theme style based on placeholder type + style_name = "bodyStyle" # Default + if self.placeholder_type and "TITLE" in self.placeholder_type: + style_name = "titleStyle" + + # Find font size in theme styles + for child in slide_master.element.iter(): + tag = child.tag.split("}")[-1] if "}" in child.tag else child.tag + if tag == style_name: + for elem in child.iter(): + if "sz" in elem.attrib: + return int(elem.attrib["sz"]) // 100 + except Exception: + pass + + return 14 # Conservative default for body text + + def _get_usable_dimensions(self, text_frame) -> Tuple[int, int]: + """Get usable width and height in pixels after accounting for margins.""" + # Default PowerPoint margins in inches + margins = {"top": 0.05, "bottom": 0.05, "left": 0.1, "right": 0.1} + + # Override with actual margins if set + if hasattr(text_frame, "margin_top") and text_frame.margin_top: + margins["top"] = self.emu_to_inches(text_frame.margin_top) + if hasattr(text_frame, "margin_bottom") and text_frame.margin_bottom: + margins["bottom"] = self.emu_to_inches(text_frame.margin_bottom) + if hasattr(text_frame, "margin_left") and text_frame.margin_left: + margins["left"] = self.emu_to_inches(text_frame.margin_left) + if hasattr(text_frame, "margin_right") and text_frame.margin_right: + margins["right"] = self.emu_to_inches(text_frame.margin_right) + + # Calculate usable area + usable_width = self.width - margins["left"] - margins["right"] + usable_height = self.height - margins["top"] - margins["bottom"] + + # Convert to pixels + return ( + self.inches_to_pixels(usable_width), + self.inches_to_pixels(usable_height), + ) + + def _wrap_text_line(self, line: str, max_width_px: int, draw, font) -> List[str]: + """Wrap a single line of text to fit within max_width_px.""" + if not line: + return [""] + + # Use textlength for efficient width calculation + if draw.textlength(line, font=font) <= max_width_px: + return [line] + + # Need to wrap - split into words + wrapped = [] + words = line.split(" ") + current_line = "" + + for word in words: + test_line = current_line + (" " if current_line else "") + word + if draw.textlength(test_line, font=font) <= max_width_px: + current_line = test_line + else: + if current_line: + wrapped.append(current_line) + current_line = word + + if current_line: + wrapped.append(current_line) + + return wrapped + + def _estimate_frame_overflow(self) -> None: + """Estimate if text overflows the shape bounds using PIL text measurement.""" + if not self.shape or not hasattr(self.shape, "text_frame"): + return + + text_frame = self.shape.text_frame # type: ignore + if not text_frame or not text_frame.paragraphs: + return + + # Get usable dimensions after accounting for margins + usable_width_px, usable_height_px = self._get_usable_dimensions(text_frame) + if usable_width_px <= 0 or usable_height_px <= 0: + return + + # Set up PIL for text measurement + dummy_img = Image.new("RGB", (1, 1)) + draw = ImageDraw.Draw(dummy_img) + + # Get default font size from placeholder or use conservative estimate + default_font_size = self._get_default_font_size() + + # Calculate total height of all paragraphs + total_height_px = 0 + + for para_idx, paragraph in enumerate(text_frame.paragraphs): + if not paragraph.text.strip(): + continue + + para_data = ParagraphData(paragraph) + + # Load font for this paragraph + font_name = para_data.font_name or "Arial" + font_size = int(para_data.font_size or default_font_size) + + font = None + font_path = self.get_font_path(font_name) + if font_path: + try: + font = ImageFont.truetype(font_path, size=font_size) + except Exception: + font = ImageFont.load_default() + else: + font = ImageFont.load_default() + + # Wrap all lines in this paragraph + all_wrapped_lines = [] + for line in paragraph.text.split("\n"): + wrapped = self._wrap_text_line(line, usable_width_px, draw, font) + all_wrapped_lines.extend(wrapped) + + if all_wrapped_lines: + # Calculate line height + if para_data.line_spacing: + # Custom line spacing explicitly set + line_height_px = para_data.line_spacing * 96 / 72 + else: + # PowerPoint default single spacing (1.0x font size) + line_height_px = font_size * 96 / 72 + + # Add space_before (except first paragraph) + if para_idx > 0 and para_data.space_before: + total_height_px += para_data.space_before * 96 / 72 + + # Add paragraph text height + total_height_px += len(all_wrapped_lines) * line_height_px + + # Add space_after + if para_data.space_after: + total_height_px += para_data.space_after * 96 / 72 + + # Check for overflow (ignore negligible overflows <= 0.05") + if total_height_px > usable_height_px: + overflow_px = total_height_px - usable_height_px + overflow_inches = round(overflow_px / 96.0, 2) + if overflow_inches > 0.05: # Only report significant overflows + self.frame_overflow_bottom = overflow_inches + + def _calculate_slide_overflow(self) -> None: + """Calculate if shape overflows the slide boundaries.""" + if self.slide_width_emu is None or self.slide_height_emu is None: + return + + # Check right overflow (ignore negligible overflows <= 0.01") + right_edge_emu = self.left_emu + self.width_emu + if right_edge_emu > self.slide_width_emu: + overflow_emu = right_edge_emu - self.slide_width_emu + overflow_inches = round(self.emu_to_inches(overflow_emu), 2) + if overflow_inches > 0.01: # Only report significant overflows + self.slide_overflow_right = overflow_inches + + # Check bottom overflow (ignore negligible overflows <= 0.01") + bottom_edge_emu = self.top_emu + self.height_emu + if bottom_edge_emu > self.slide_height_emu: + overflow_emu = bottom_edge_emu - self.slide_height_emu + overflow_inches = round(self.emu_to_inches(overflow_emu), 2) + if overflow_inches > 0.01: # Only report significant overflows + self.slide_overflow_bottom = overflow_inches + + def _detect_bullet_issues(self) -> None: + """Detect bullet point formatting issues in paragraphs.""" + if not self.shape or not hasattr(self.shape, "text_frame"): + return + + text_frame = self.shape.text_frame # type: ignore + if not text_frame or not text_frame.paragraphs: + return + + # Common bullet symbols that indicate manual bullets + bullet_symbols = ["•", "●", "○"] + + for paragraph in text_frame.paragraphs: + text = paragraph.text.strip() + # Check for manual bullet symbols + if text and any(text.startswith(symbol + " ") for symbol in bullet_symbols): + self.warnings.append( + "manual_bullet_symbol: use proper bullet formatting" + ) + break + + @property + def has_any_issues(self) -> bool: + """Check if shape has any issues (overflow, overlap, or warnings).""" + return ( + self.frame_overflow_bottom is not None + or self.slide_overflow_right is not None + or self.slide_overflow_bottom is not None + or len(self.overlapping_shapes) > 0 + or len(self.warnings) > 0 + ) + + def to_dict(self) -> ShapeDict: + """Convert to dictionary for JSON serialization.""" + result: ShapeDict = { + "left": self.left, + "top": self.top, + "width": self.width, + "height": self.height, + } + + # Add optional fields if present + if self.placeholder_type: + result["placeholder_type"] = self.placeholder_type + + if self.default_font_size: + result["default_font_size"] = self.default_font_size + + # Add overflow information only if there is overflow + overflow_data = {} + + # Add frame overflow if present + if self.frame_overflow_bottom is not None: + overflow_data["frame"] = {"overflow_bottom": self.frame_overflow_bottom} + + # Add slide overflow if present + slide_overflow = {} + if self.slide_overflow_right is not None: + slide_overflow["overflow_right"] = self.slide_overflow_right + if self.slide_overflow_bottom is not None: + slide_overflow["overflow_bottom"] = self.slide_overflow_bottom + if slide_overflow: + overflow_data["slide"] = slide_overflow + + # Only add overflow field if there is overflow + if overflow_data: + result["overflow"] = overflow_data + + # Add overlap field if there are overlapping shapes + if self.overlapping_shapes: + result["overlap"] = {"overlapping_shapes": self.overlapping_shapes} + + # Add warnings field if there are warnings + if self.warnings: + result["warnings"] = self.warnings + + # Add paragraphs after placeholder_type + result["paragraphs"] = [para.to_dict() for para in self.paragraphs] + + return result + + +def is_valid_shape(shape: BaseShape) -> bool: + """Check if a shape contains meaningful text content.""" + # Must have a text frame with content + if not hasattr(shape, "text_frame") or not shape.text_frame: # type: ignore + return False + + text = shape.text_frame.text.strip() # type: ignore + if not text: + return False + + # Skip slide numbers and numeric footers + if hasattr(shape, "is_placeholder") and shape.is_placeholder: # type: ignore + if shape.placeholder_format and shape.placeholder_format.type: # type: ignore + placeholder_type = ( + str(shape.placeholder_format.type).split(".")[-1].split(" ")[0] # type: ignore + ) + if placeholder_type == "SLIDE_NUMBER": + return False + if placeholder_type == "FOOTER" and text.isdigit(): + return False + + return True + + +def collect_shapes_with_absolute_positions( + shape: BaseShape, parent_left: int = 0, parent_top: int = 0 +) -> List[ShapeWithPosition]: + """Recursively collect all shapes with valid text, calculating absolute positions. + + For shapes within groups, their positions are relative to the group. + This function calculates the absolute position on the slide by accumulating + parent group offsets. + + Args: + shape: The shape to process + parent_left: Accumulated left offset from parent groups (in EMUs) + parent_top: Accumulated top offset from parent groups (in EMUs) + + Returns: + List of ShapeWithPosition objects with absolute positions + """ + if hasattr(shape, "shapes"): # GroupShape + result = [] + # Get this group's position + group_left = shape.left if hasattr(shape, "left") else 0 + group_top = shape.top if hasattr(shape, "top") else 0 + + # Calculate absolute position for this group + abs_group_left = parent_left + group_left + abs_group_top = parent_top + group_top + + # Process children with accumulated offsets + for child in shape.shapes: # type: ignore + result.extend( + collect_shapes_with_absolute_positions( + child, abs_group_left, abs_group_top + ) + ) + return result + + # Regular shape - check if it has valid text + if is_valid_shape(shape): + # Calculate absolute position + shape_left = shape.left if hasattr(shape, "left") else 0 + shape_top = shape.top if hasattr(shape, "top") else 0 + + return [ + ShapeWithPosition( + shape=shape, + absolute_left=parent_left + shape_left, + absolute_top=parent_top + shape_top, + ) + ] + + return [] + + +def sort_shapes_by_position(shapes: List[ShapeData]) -> List[ShapeData]: + """Sort shapes by visual position (top-to-bottom, left-to-right). + + Shapes within 0.5 inches vertically are considered on the same row. + """ + if not shapes: + return shapes + + # Sort by top position first + shapes = sorted(shapes, key=lambda s: (s.top, s.left)) + + # Group shapes by row (within 0.5 inches vertically) + result = [] + row = [shapes[0]] + row_top = shapes[0].top + + for shape in shapes[1:]: + if abs(shape.top - row_top) <= 0.5: + row.append(shape) + else: + # Sort current row by left position and add to result + result.extend(sorted(row, key=lambda s: s.left)) + row = [shape] + row_top = shape.top + + # Don't forget the last row + result.extend(sorted(row, key=lambda s: s.left)) + return result + + +def calculate_overlap( + rect1: Tuple[float, float, float, float], + rect2: Tuple[float, float, float, float], + tolerance: float = 0.05, +) -> Tuple[bool, float]: + """Calculate if and how much two rectangles overlap. + + Args: + rect1: (left, top, width, height) of first rectangle in inches + rect2: (left, top, width, height) of second rectangle in inches + tolerance: Minimum overlap in inches to consider as overlapping (default: 0.05") + + Returns: + Tuple of (overlaps, overlap_area) where: + - overlaps: True if rectangles overlap by more than tolerance + - overlap_area: Area of overlap in square inches + """ + left1, top1, w1, h1 = rect1 + left2, top2, w2, h2 = rect2 + + # Calculate overlap dimensions + overlap_width = min(left1 + w1, left2 + w2) - max(left1, left2) + overlap_height = min(top1 + h1, top2 + h2) - max(top1, top2) + + # Check if there's meaningful overlap (more than tolerance) + if overlap_width > tolerance and overlap_height > tolerance: + # Calculate overlap area in square inches + overlap_area = overlap_width * overlap_height + return True, round(overlap_area, 2) + + return False, 0 + + +def detect_overlaps(shapes: List[ShapeData]) -> None: + """Detect overlapping shapes and update their overlapping_shapes dictionaries. + + This function requires each ShapeData to have its shape_id already set. + It modifies the shapes in-place, adding shape IDs with overlap areas in square inches. + + Args: + shapes: List of ShapeData objects with shape_id attributes set + """ + n = len(shapes) + + # Compare each pair of shapes + for i in range(n): + for j in range(i + 1, n): + shape1 = shapes[i] + shape2 = shapes[j] + + # Ensure shape IDs are set + assert shape1.shape_id, f"Shape at index {i} has no shape_id" + assert shape2.shape_id, f"Shape at index {j} has no shape_id" + + rect1 = (shape1.left, shape1.top, shape1.width, shape1.height) + rect2 = (shape2.left, shape2.top, shape2.width, shape2.height) + + overlaps, overlap_area = calculate_overlap(rect1, rect2) + + if overlaps: + # Add shape IDs with overlap area in square inches + shape1.overlapping_shapes[shape2.shape_id] = overlap_area + shape2.overlapping_shapes[shape1.shape_id] = overlap_area + + +def extract_text_inventory( + pptx_path: Path, prs: Optional[Any] = None, issues_only: bool = False +) -> InventoryData: + """Extract text content from all slides in a PowerPoint presentation. + + Args: + pptx_path: Path to the PowerPoint file + prs: Optional Presentation object to use. If not provided, will load from pptx_path. + issues_only: If True, only include shapes that have overflow or overlap issues + + Returns a nested dictionary: {slide-N: {shape-N: ShapeData}} + Shapes are sorted by visual position (top-to-bottom, left-to-right). + The ShapeData objects contain the full shape information and can be + converted to dictionaries for JSON serialization using to_dict(). + """ + if prs is None: + prs = Presentation(str(pptx_path)) + inventory: InventoryData = {} + + for slide_idx, slide in enumerate(prs.slides): + # Collect all valid shapes from this slide with absolute positions + shapes_with_positions = [] + for shape in slide.shapes: # type: ignore + shapes_with_positions.extend(collect_shapes_with_absolute_positions(shape)) + + if not shapes_with_positions: + continue + + # Convert to ShapeData with absolute positions and slide reference + shape_data_list = [ + ShapeData( + swp.shape, + swp.absolute_left, + swp.absolute_top, + slide, + ) + for swp in shapes_with_positions + ] + + # Sort by visual position and assign stable IDs in one step + sorted_shapes = sort_shapes_by_position(shape_data_list) + for idx, shape_data in enumerate(sorted_shapes): + shape_data.shape_id = f"shape-{idx}" + + # Detect overlaps using the stable shape IDs + if len(sorted_shapes) > 1: + detect_overlaps(sorted_shapes) + + # Filter for issues only if requested (after overlap detection) + if issues_only: + sorted_shapes = [sd for sd in sorted_shapes if sd.has_any_issues] + + if not sorted_shapes: + continue + + # Create slide inventory using the stable shape IDs + inventory[f"slide-{slide_idx}"] = { + shape_data.shape_id: shape_data for shape_data in sorted_shapes + } + + return inventory + + +def get_inventory_as_dict(pptx_path: Path, issues_only: bool = False) -> InventoryDict: + """Extract text inventory and return as JSON-serializable dictionaries. + + This is a convenience wrapper around extract_text_inventory that returns + dictionaries instead of ShapeData objects, useful for testing and direct + JSON serialization. + + Args: + pptx_path: Path to the PowerPoint file + issues_only: If True, only include shapes that have overflow or overlap issues + + Returns: + Nested dictionary with all data serialized for JSON + """ + inventory = extract_text_inventory(pptx_path, issues_only=issues_only) + + # Convert ShapeData objects to dictionaries + dict_inventory: InventoryDict = {} + for slide_key, shapes in inventory.items(): + dict_inventory[slide_key] = { + shape_key: shape_data.to_dict() for shape_key, shape_data in shapes.items() + } + + return dict_inventory + + +def save_inventory(inventory: InventoryData, output_path: Path) -> None: + """Save inventory to JSON file with proper formatting. + + Converts ShapeData objects to dictionaries for JSON serialization. + """ + # Convert ShapeData objects to dictionaries + json_inventory: InventoryDict = {} + for slide_key, shapes in inventory.items(): + json_inventory[slide_key] = { + shape_key: shape_data.to_dict() for shape_key, shape_data in shapes.items() + } + + with open(output_path, "w", encoding="utf-8") as f: + json.dump(json_inventory, f, indent=2, ensure_ascii=False) + + +if __name__ == "__main__": + main() diff --git a/skills/pptx/scripts/rearrange.py b/skills/pptx/scripts/rearrange.py new file mode 100755 index 0000000..2519911 --- /dev/null +++ b/skills/pptx/scripts/rearrange.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python3 +""" +Rearrange PowerPoint slides based on a sequence of indices. + +Usage: + python rearrange.py template.pptx output.pptx 0,34,34,50,52 + +This will create output.pptx using slides from template.pptx in the specified order. +Slides can be repeated (e.g., 34 appears twice). +""" + +import argparse +import shutil +import sys +from copy import deepcopy +from pathlib import Path + +import six +from pptx import Presentation + + +def main(): + parser = argparse.ArgumentParser( + description="Rearrange PowerPoint slides based on a sequence of indices.", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + python rearrange.py template.pptx output.pptx 0,34,34,50,52 + Creates output.pptx using slides 0, 34 (twice), 50, and 52 from template.pptx + + python rearrange.py template.pptx output.pptx 5,3,1,2,4 + Creates output.pptx with slides reordered as specified + +Note: Slide indices are 0-based (first slide is 0, second is 1, etc.) + """, + ) + + parser.add_argument("template", help="Path to template PPTX file") + parser.add_argument("output", help="Path for output PPTX file") + parser.add_argument( + "sequence", help="Comma-separated sequence of slide indices (0-based)" + ) + + args = parser.parse_args() + + # Parse the slide sequence + try: + slide_sequence = [int(x.strip()) for x in args.sequence.split(",")] + except ValueError: + print( + "Error: Invalid sequence format. Use comma-separated integers (e.g., 0,34,34,50,52)" + ) + sys.exit(1) + + # Check template exists + template_path = Path(args.template) + if not template_path.exists(): + print(f"Error: Template file not found: {args.template}") + sys.exit(1) + + # Create output directory if needed + output_path = Path(args.output) + output_path.parent.mkdir(parents=True, exist_ok=True) + + try: + rearrange_presentation(template_path, output_path, slide_sequence) + except ValueError as e: + print(f"Error: {e}") + sys.exit(1) + except Exception as e: + print(f"Error processing presentation: {e}") + sys.exit(1) + + +def duplicate_slide(pres, index): + """Duplicate a slide in the presentation.""" + source = pres.slides[index] + + # Use source's layout to preserve formatting + new_slide = pres.slides.add_slide(source.slide_layout) + + # Collect all image and media relationships from the source slide + image_rels = {} + for rel_id, rel in six.iteritems(source.part.rels): + if "image" in rel.reltype or "media" in rel.reltype: + image_rels[rel_id] = rel + + # CRITICAL: Clear placeholder shapes to avoid duplicates + for shape in new_slide.shapes: + sp = shape.element + sp.getparent().remove(sp) + + # Copy all shapes from source + for shape in source.shapes: + el = shape.element + new_el = deepcopy(el) + new_slide.shapes._spTree.insert_element_before(new_el, "p:extLst") + + # Handle picture shapes - need to update the blip reference + # Look for all blip elements (they can be in pic or other contexts) + # Using the element's own xpath method without namespaces argument + blips = new_el.xpath(".//a:blip[@r:embed]") + for blip in blips: + old_rId = blip.get( + "{http://schemas.openxmlformats.org/officeDocument/2006/relationships}embed" + ) + if old_rId in image_rels: + # Create a new relationship in the destination slide for this image + old_rel = image_rels[old_rId] + # get_or_add returns the rId directly, or adds and returns new rId + new_rId = new_slide.part.rels.get_or_add( + old_rel.reltype, old_rel._target + ) + # Update the blip's embed reference to use the new relationship ID + blip.set( + "{http://schemas.openxmlformats.org/officeDocument/2006/relationships}embed", + new_rId, + ) + + # Copy any additional image/media relationships that might be referenced elsewhere + for rel_id, rel in image_rels.items(): + try: + new_slide.part.rels.get_or_add(rel.reltype, rel._target) + except Exception: + pass # Relationship might already exist + + return new_slide + + +def delete_slide(pres, index): + """Delete a slide from the presentation.""" + rId = pres.slides._sldIdLst[index].rId + pres.part.drop_rel(rId) + del pres.slides._sldIdLst[index] + + +def reorder_slides(pres, slide_index, target_index): + """Move a slide from one position to another.""" + slides = pres.slides._sldIdLst + + # Remove slide element from current position + slide_element = slides[slide_index] + slides.remove(slide_element) + + # Insert at target position + slides.insert(target_index, slide_element) + + +def rearrange_presentation(template_path, output_path, slide_sequence): + """ + Create a new presentation with slides from template in specified order. + + Args: + template_path: Path to template PPTX file + output_path: Path for output PPTX file + slide_sequence: List of slide indices (0-based) to include + """ + # Copy template to preserve dimensions and theme + if template_path != output_path: + shutil.copy2(template_path, output_path) + prs = Presentation(output_path) + else: + prs = Presentation(template_path) + + total_slides = len(prs.slides) + + # Validate indices + for idx in slide_sequence: + if idx < 0 or idx >= total_slides: + raise ValueError(f"Slide index {idx} out of range (0-{total_slides - 1})") + + # Track original slides and their duplicates + slide_map = [] # List of actual slide indices for final presentation + duplicated = {} # Track duplicates: original_idx -> [duplicate_indices] + + # Step 1: DUPLICATE repeated slides + print(f"Processing {len(slide_sequence)} slides from template...") + for i, template_idx in enumerate(slide_sequence): + if template_idx in duplicated and duplicated[template_idx]: + # Already duplicated this slide, use the duplicate + slide_map.append(duplicated[template_idx].pop(0)) + print(f" [{i}] Using duplicate of slide {template_idx}") + elif slide_sequence.count(template_idx) > 1 and template_idx not in duplicated: + # First occurrence of a repeated slide - create duplicates + slide_map.append(template_idx) + duplicates = [] + count = slide_sequence.count(template_idx) - 1 + print( + f" [{i}] Using original slide {template_idx}, creating {count} duplicate(s)" + ) + for _ in range(count): + duplicate_slide(prs, template_idx) + duplicates.append(len(prs.slides) - 1) + duplicated[template_idx] = duplicates + else: + # Unique slide or first occurrence already handled, use original + slide_map.append(template_idx) + print(f" [{i}] Using original slide {template_idx}") + + # Step 2: DELETE unwanted slides (work backwards) + slides_to_keep = set(slide_map) + print(f"\nDeleting {len(prs.slides) - len(slides_to_keep)} unused slides...") + for i in range(len(prs.slides) - 1, -1, -1): + if i not in slides_to_keep: + delete_slide(prs, i) + # Update slide_map indices after deletion + slide_map = [idx - 1 if idx > i else idx for idx in slide_map] + + # Step 3: REORDER to final sequence + print(f"Reordering {len(slide_map)} slides to final sequence...") + for target_pos in range(len(slide_map)): + # Find which slide should be at target_pos + current_pos = slide_map[target_pos] + if current_pos != target_pos: + reorder_slides(prs, current_pos, target_pos) + # Update slide_map: the move shifts other slides + for i in range(len(slide_map)): + if slide_map[i] > current_pos and slide_map[i] <= target_pos: + slide_map[i] -= 1 + elif slide_map[i] < current_pos and slide_map[i] >= target_pos: + slide_map[i] += 1 + slide_map[target_pos] = target_pos + + # Save the presentation + prs.save(output_path) + print(f"\nSaved rearranged presentation to: {output_path}") + print(f"Final presentation has {len(prs.slides)} slides") + + +if __name__ == "__main__": + main() diff --git a/skills/pptx/scripts/replace.py b/skills/pptx/scripts/replace.py new file mode 100755 index 0000000..8f7a8b1 --- /dev/null +++ b/skills/pptx/scripts/replace.py @@ -0,0 +1,385 @@ +#!/usr/bin/env python3 +"""Apply text replacements to PowerPoint presentation. + +Usage: + python replace.py <input.pptx> <replacements.json> <output.pptx> + +The replacements JSON should have the structure output by inventory.py. +ALL text shapes identified by inventory.py will have their text cleared +unless "paragraphs" is specified in the replacements for that shape. +""" + +import json +import sys +from pathlib import Path +from typing import Any, Dict, List + +from inventory import InventoryData, extract_text_inventory +from pptx import Presentation +from pptx.dml.color import RGBColor +from pptx.enum.dml import MSO_THEME_COLOR +from pptx.enum.text import PP_ALIGN +from pptx.oxml.xmlchemy import OxmlElement +from pptx.util import Pt + + +def clear_paragraph_bullets(paragraph): + """Clear bullet formatting from a paragraph.""" + pPr = paragraph._element.get_or_add_pPr() + + # Remove existing bullet elements + for child in list(pPr): + if ( + child.tag.endswith("buChar") + or child.tag.endswith("buNone") + or child.tag.endswith("buAutoNum") + or child.tag.endswith("buFont") + ): + pPr.remove(child) + + return pPr + + +def apply_paragraph_properties(paragraph, para_data: Dict[str, Any]): + """Apply formatting properties to a paragraph.""" + # Get the text but don't set it on paragraph directly yet + text = para_data.get("text", "") + + # Get or create paragraph properties + pPr = clear_paragraph_bullets(paragraph) + + # Handle bullet formatting + if para_data.get("bullet", False): + level = para_data.get("level", 0) + paragraph.level = level + + # Calculate font-proportional indentation + font_size = para_data.get("font_size", 18.0) + level_indent_emu = int((font_size * (1.6 + level * 1.6)) * 12700) + hanging_indent_emu = int(-font_size * 0.8 * 12700) + + # Set indentation + pPr.attrib["marL"] = str(level_indent_emu) + pPr.attrib["indent"] = str(hanging_indent_emu) + + # Add bullet character + buChar = OxmlElement("a:buChar") + buChar.set("char", "•") + pPr.append(buChar) + + # Default to left alignment for bullets if not specified + if "alignment" not in para_data: + paragraph.alignment = PP_ALIGN.LEFT + else: + # Remove indentation for non-bullet text + pPr.attrib["marL"] = "0" + pPr.attrib["indent"] = "0" + + # Add buNone element + buNone = OxmlElement("a:buNone") + pPr.insert(0, buNone) + + # Apply alignment + if "alignment" in para_data: + alignment_map = { + "LEFT": PP_ALIGN.LEFT, + "CENTER": PP_ALIGN.CENTER, + "RIGHT": PP_ALIGN.RIGHT, + "JUSTIFY": PP_ALIGN.JUSTIFY, + } + if para_data["alignment"] in alignment_map: + paragraph.alignment = alignment_map[para_data["alignment"]] + + # Apply spacing + if "space_before" in para_data: + paragraph.space_before = Pt(para_data["space_before"]) + if "space_after" in para_data: + paragraph.space_after = Pt(para_data["space_after"]) + if "line_spacing" in para_data: + paragraph.line_spacing = Pt(para_data["line_spacing"]) + + # Apply run-level formatting + if not paragraph.runs: + run = paragraph.add_run() + run.text = text + else: + run = paragraph.runs[0] + run.text = text + + # Apply font properties + apply_font_properties(run, para_data) + + +def apply_font_properties(run, para_data: Dict[str, Any]): + """Apply font properties to a text run.""" + if "bold" in para_data: + run.font.bold = para_data["bold"] + if "italic" in para_data: + run.font.italic = para_data["italic"] + if "underline" in para_data: + run.font.underline = para_data["underline"] + if "font_size" in para_data: + run.font.size = Pt(para_data["font_size"]) + if "font_name" in para_data: + run.font.name = para_data["font_name"] + + # Apply color - prefer RGB, fall back to theme_color + if "color" in para_data: + color_hex = para_data["color"].lstrip("#") + if len(color_hex) == 6: + r = int(color_hex[0:2], 16) + g = int(color_hex[2:4], 16) + b = int(color_hex[4:6], 16) + run.font.color.rgb = RGBColor(r, g, b) + elif "theme_color" in para_data: + # Get theme color by name (e.g., "DARK_1", "ACCENT_1") + theme_name = para_data["theme_color"] + try: + run.font.color.theme_color = getattr(MSO_THEME_COLOR, theme_name) + except AttributeError: + print(f" WARNING: Unknown theme color name '{theme_name}'") + + +def detect_frame_overflow(inventory: InventoryData) -> Dict[str, Dict[str, float]]: + """Detect text overflow in shapes (text exceeding shape bounds). + + Returns dict of slide_key -> shape_key -> overflow_inches. + Only includes shapes that have text overflow. + """ + overflow_map = {} + + for slide_key, shapes_dict in inventory.items(): + for shape_key, shape_data in shapes_dict.items(): + # Check for frame overflow (text exceeding shape bounds) + if shape_data.frame_overflow_bottom is not None: + if slide_key not in overflow_map: + overflow_map[slide_key] = {} + overflow_map[slide_key][shape_key] = shape_data.frame_overflow_bottom + + return overflow_map + + +def validate_replacements(inventory: InventoryData, replacements: Dict) -> List[str]: + """Validate that all shapes in replacements exist in inventory. + + Returns list of error messages. + """ + errors = [] + + for slide_key, shapes_data in replacements.items(): + if not slide_key.startswith("slide-"): + continue + + # Check if slide exists + if slide_key not in inventory: + errors.append(f"Slide '{slide_key}' not found in inventory") + continue + + # Check each shape + for shape_key in shapes_data.keys(): + if shape_key not in inventory[slide_key]: + # Find shapes without replacements defined and show their content + unused_with_content = [] + for k in inventory[slide_key].keys(): + if k not in shapes_data: + shape_data = inventory[slide_key][k] + # Get text from paragraphs as preview + paragraphs = shape_data.paragraphs + if paragraphs and paragraphs[0].text: + first_text = paragraphs[0].text[:50] + if len(paragraphs[0].text) > 50: + first_text += "..." + unused_with_content.append(f"{k} ('{first_text}')") + else: + unused_with_content.append(k) + + errors.append( + f"Shape '{shape_key}' not found on '{slide_key}'. " + f"Shapes without replacements: {', '.join(sorted(unused_with_content)) if unused_with_content else 'none'}" + ) + + return errors + + +def check_duplicate_keys(pairs): + """Check for duplicate keys when loading JSON.""" + result = {} + for key, value in pairs: + if key in result: + raise ValueError(f"Duplicate key found in JSON: '{key}'") + result[key] = value + return result + + +def apply_replacements(pptx_file: str, json_file: str, output_file: str): + """Apply text replacements from JSON to PowerPoint presentation.""" + + # Load presentation + prs = Presentation(pptx_file) + + # Get inventory of all text shapes (returns ShapeData objects) + # Pass prs to use same Presentation instance + inventory = extract_text_inventory(Path(pptx_file), prs) + + # Detect text overflow in original presentation + original_overflow = detect_frame_overflow(inventory) + + # Load replacement data with duplicate key detection + with open(json_file, "r") as f: + replacements = json.load(f, object_pairs_hook=check_duplicate_keys) + + # Validate replacements + errors = validate_replacements(inventory, replacements) + if errors: + print("ERROR: Invalid shapes in replacement JSON:") + for error in errors: + print(f" - {error}") + print("\nPlease check the inventory and update your replacement JSON.") + print( + "You can regenerate the inventory with: python inventory.py <input.pptx> <output.json>" + ) + raise ValueError(f"Found {len(errors)} validation error(s)") + + # Track statistics + shapes_processed = 0 + shapes_cleared = 0 + shapes_replaced = 0 + + # Process each slide from inventory + for slide_key, shapes_dict in inventory.items(): + if not slide_key.startswith("slide-"): + continue + + slide_index = int(slide_key.split("-")[1]) + + if slide_index >= len(prs.slides): + print(f"Warning: Slide {slide_index} not found") + continue + + # Process each shape from inventory + for shape_key, shape_data in shapes_dict.items(): + shapes_processed += 1 + + # Get the shape directly from ShapeData + shape = shape_data.shape + if not shape: + print(f"Warning: {shape_key} has no shape reference") + continue + + # ShapeData already validates text_frame in __init__ + text_frame = shape.text_frame # type: ignore + + text_frame.clear() # type: ignore + shapes_cleared += 1 + + # Check for replacement paragraphs + replacement_shape_data = replacements.get(slide_key, {}).get(shape_key, {}) + if "paragraphs" not in replacement_shape_data: + continue + + shapes_replaced += 1 + + # Add replacement paragraphs + for i, para_data in enumerate(replacement_shape_data["paragraphs"]): + if i == 0: + p = text_frame.paragraphs[0] # type: ignore + else: + p = text_frame.add_paragraph() # type: ignore + + apply_paragraph_properties(p, para_data) + + # Check for issues after replacements + # Save to a temporary file and reload to avoid modifying the presentation during inventory + # (extract_text_inventory accesses font.color which adds empty <a:solidFill/> elements) + import tempfile + + with tempfile.NamedTemporaryFile(suffix=".pptx", delete=False) as tmp: + tmp_path = Path(tmp.name) + prs.save(str(tmp_path)) + + try: + updated_inventory = extract_text_inventory(tmp_path) + updated_overflow = detect_frame_overflow(updated_inventory) + finally: + tmp_path.unlink() # Clean up temp file + + # Check if any text overflow got worse + overflow_errors = [] + for slide_key, shape_overflows in updated_overflow.items(): + for shape_key, new_overflow in shape_overflows.items(): + # Get original overflow (0 if there was no overflow before) + original = original_overflow.get(slide_key, {}).get(shape_key, 0.0) + + # Error if overflow increased + if new_overflow > original + 0.01: # Small tolerance for rounding + increase = new_overflow - original + overflow_errors.append( + f'{slide_key}/{shape_key}: overflow worsened by {increase:.2f}" ' + f'(was {original:.2f}", now {new_overflow:.2f}")' + ) + + # Collect warnings from updated shapes + warnings = [] + for slide_key, shapes_dict in updated_inventory.items(): + for shape_key, shape_data in shapes_dict.items(): + if shape_data.warnings: + for warning in shape_data.warnings: + warnings.append(f"{slide_key}/{shape_key}: {warning}") + + # Fail if there are any issues + if overflow_errors or warnings: + print("\nERROR: Issues detected in replacement output:") + if overflow_errors: + print("\nText overflow worsened:") + for error in overflow_errors: + print(f" - {error}") + if warnings: + print("\nFormatting warnings:") + for warning in warnings: + print(f" - {warning}") + print("\nPlease fix these issues before saving.") + raise ValueError( + f"Found {len(overflow_errors)} overflow error(s) and {len(warnings)} warning(s)" + ) + + # Save the presentation + prs.save(output_file) + + # Report results + print(f"Saved updated presentation to: {output_file}") + print(f"Processed {len(prs.slides)} slides") + print(f" - Shapes processed: {shapes_processed}") + print(f" - Shapes cleared: {shapes_cleared}") + print(f" - Shapes replaced: {shapes_replaced}") + + +def main(): + """Main entry point for command-line usage.""" + if len(sys.argv) != 4: + print(__doc__) + sys.exit(1) + + input_pptx = Path(sys.argv[1]) + replacements_json = Path(sys.argv[2]) + output_pptx = Path(sys.argv[3]) + + if not input_pptx.exists(): + print(f"Error: Input file '{input_pptx}' not found") + sys.exit(1) + + if not replacements_json.exists(): + print(f"Error: Replacements JSON file '{replacements_json}' not found") + sys.exit(1) + + try: + apply_replacements(str(input_pptx), str(replacements_json), str(output_pptx)) + except Exception as e: + print(f"Error applying replacements: {e}") + import traceback + + traceback.print_exc() + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/skills/pptx/scripts/thumbnail.py b/skills/pptx/scripts/thumbnail.py new file mode 100755 index 0000000..5c7fdf1 --- /dev/null +++ b/skills/pptx/scripts/thumbnail.py @@ -0,0 +1,450 @@ +#!/usr/bin/env python3 +""" +Create thumbnail grids from PowerPoint presentation slides. + +Creates a grid layout of slide thumbnails with configurable columns (max 6). +Each grid contains up to cols×(cols+1) images. For presentations with more +slides, multiple numbered grid files are created automatically. + +The program outputs the names of all files created. + +Output: +- Single grid: {prefix}.jpg (if slides fit in one grid) +- Multiple grids: {prefix}-1.jpg, {prefix}-2.jpg, etc. + +Grid limits by column count: +- 3 cols: max 12 slides per grid (3×4) +- 4 cols: max 20 slides per grid (4×5) +- 5 cols: max 30 slides per grid (5×6) [default] +- 6 cols: max 42 slides per grid (6×7) + +Usage: + python thumbnail.py input.pptx [output_prefix] [--cols N] [--outline-placeholders] + +Examples: + python thumbnail.py presentation.pptx + # Creates: thumbnails.jpg (using default prefix) + # Outputs: + # Created 1 grid(s): + # - thumbnails.jpg + + python thumbnail.py large-deck.pptx grid --cols 4 + # Creates: grid-1.jpg, grid-2.jpg, grid-3.jpg + # Outputs: + # Created 3 grid(s): + # - grid-1.jpg + # - grid-2.jpg + # - grid-3.jpg + + python thumbnail.py template.pptx analysis --outline-placeholders + # Creates thumbnail grids with red outlines around text placeholders +""" + +import argparse +import subprocess +import sys +import tempfile +from pathlib import Path + +from inventory import extract_text_inventory +from PIL import Image, ImageDraw, ImageFont +from pptx import Presentation + +# Constants +THUMBNAIL_WIDTH = 300 # Fixed thumbnail width in pixels +CONVERSION_DPI = 100 # DPI for PDF to image conversion +MAX_COLS = 6 # Maximum number of columns +DEFAULT_COLS = 5 # Default number of columns +JPEG_QUALITY = 95 # JPEG compression quality + +# Grid layout constants +GRID_PADDING = 20 # Padding between thumbnails +BORDER_WIDTH = 2 # Border width around thumbnails +FONT_SIZE_RATIO = 0.12 # Font size as fraction of thumbnail width +LABEL_PADDING_RATIO = 0.4 # Label padding as fraction of font size + + +def main(): + parser = argparse.ArgumentParser( + description="Create thumbnail grids from PowerPoint slides." + ) + parser.add_argument("input", help="Input PowerPoint file (.pptx)") + parser.add_argument( + "output_prefix", + nargs="?", + default="thumbnails", + help="Output prefix for image files (default: thumbnails, will create prefix.jpg or prefix-N.jpg)", + ) + parser.add_argument( + "--cols", + type=int, + default=DEFAULT_COLS, + help=f"Number of columns (default: {DEFAULT_COLS}, max: {MAX_COLS})", + ) + parser.add_argument( + "--outline-placeholders", + action="store_true", + help="Outline text placeholders with a colored border", + ) + + args = parser.parse_args() + + # Validate columns + cols = min(args.cols, MAX_COLS) + if args.cols > MAX_COLS: + print(f"Warning: Columns limited to {MAX_COLS} (requested {args.cols})") + + # Validate input + input_path = Path(args.input) + if not input_path.exists() or input_path.suffix.lower() != ".pptx": + print(f"Error: Invalid PowerPoint file: {args.input}") + sys.exit(1) + + # Construct output path (always JPG) + output_path = Path(f"{args.output_prefix}.jpg") + + print(f"Processing: {args.input}") + + try: + with tempfile.TemporaryDirectory() as temp_dir: + # Get placeholder regions if outlining is enabled + placeholder_regions = None + slide_dimensions = None + if args.outline_placeholders: + print("Extracting placeholder regions...") + placeholder_regions, slide_dimensions = get_placeholder_regions( + input_path + ) + if placeholder_regions: + print(f"Found placeholders on {len(placeholder_regions)} slides") + + # Convert slides to images + slide_images = convert_to_images(input_path, Path(temp_dir), CONVERSION_DPI) + if not slide_images: + print("Error: No slides found") + sys.exit(1) + + print(f"Found {len(slide_images)} slides") + + # Create grids (max cols×(cols+1) images per grid) + grid_files = create_grids( + slide_images, + cols, + THUMBNAIL_WIDTH, + output_path, + placeholder_regions, + slide_dimensions, + ) + + # Print saved files + print(f"Created {len(grid_files)} grid(s):") + for grid_file in grid_files: + print(f" - {grid_file}") + + except Exception as e: + print(f"Error: {e}") + sys.exit(1) + + +def create_hidden_slide_placeholder(size): + """Create placeholder image for hidden slides.""" + img = Image.new("RGB", size, color="#F0F0F0") + draw = ImageDraw.Draw(img) + line_width = max(5, min(size) // 100) + draw.line([(0, 0), size], fill="#CCCCCC", width=line_width) + draw.line([(size[0], 0), (0, size[1])], fill="#CCCCCC", width=line_width) + return img + + +def get_placeholder_regions(pptx_path): + """Extract ALL text regions from the presentation. + + Returns a tuple of (placeholder_regions, slide_dimensions). + text_regions is a dict mapping slide indices to lists of text regions. + Each region is a dict with 'left', 'top', 'width', 'height' in inches. + slide_dimensions is a tuple of (width_inches, height_inches). + """ + prs = Presentation(str(pptx_path)) + inventory = extract_text_inventory(pptx_path, prs) + placeholder_regions = {} + + # Get actual slide dimensions in inches (EMU to inches conversion) + slide_width_inches = (prs.slide_width or 9144000) / 914400.0 + slide_height_inches = (prs.slide_height or 5143500) / 914400.0 + + for slide_key, shapes in inventory.items(): + # Extract slide index from "slide-N" format + slide_idx = int(slide_key.split("-")[1]) + regions = [] + + for shape_key, shape_data in shapes.items(): + # The inventory only contains shapes with text, so all shapes should be highlighted + regions.append( + { + "left": shape_data.left, + "top": shape_data.top, + "width": shape_data.width, + "height": shape_data.height, + } + ) + + if regions: + placeholder_regions[slide_idx] = regions + + return placeholder_regions, (slide_width_inches, slide_height_inches) + + +def convert_to_images(pptx_path, temp_dir, dpi): + """Convert PowerPoint to images via PDF, handling hidden slides.""" + # Detect hidden slides + print("Analyzing presentation...") + prs = Presentation(str(pptx_path)) + total_slides = len(prs.slides) + + # Find hidden slides (1-based indexing for display) + hidden_slides = { + idx + 1 + for idx, slide in enumerate(prs.slides) + if slide.element.get("show") == "0" + } + + print(f"Total slides: {total_slides}") + if hidden_slides: + print(f"Hidden slides: {sorted(hidden_slides)}") + + pdf_path = temp_dir / f"{pptx_path.stem}.pdf" + + # Convert to PDF + print("Converting to PDF...") + result = subprocess.run( + [ + "soffice", + "--headless", + "--convert-to", + "pdf", + "--outdir", + str(temp_dir), + str(pptx_path), + ], + capture_output=True, + text=True, + ) + if result.returncode != 0 or not pdf_path.exists(): + raise RuntimeError("PDF conversion failed") + + # Convert PDF to images + print(f"Converting to images at {dpi} DPI...") + result = subprocess.run( + ["pdftoppm", "-jpeg", "-r", str(dpi), str(pdf_path), str(temp_dir / "slide")], + capture_output=True, + text=True, + ) + if result.returncode != 0: + raise RuntimeError("Image conversion failed") + + visible_images = sorted(temp_dir.glob("slide-*.jpg")) + + # Create full list with placeholders for hidden slides + all_images = [] + visible_idx = 0 + + # Get placeholder dimensions from first visible slide + if visible_images: + with Image.open(visible_images[0]) as img: + placeholder_size = img.size + else: + placeholder_size = (1920, 1080) + + for slide_num in range(1, total_slides + 1): + if slide_num in hidden_slides: + # Create placeholder image for hidden slide + placeholder_path = temp_dir / f"hidden-{slide_num:03d}.jpg" + placeholder_img = create_hidden_slide_placeholder(placeholder_size) + placeholder_img.save(placeholder_path, "JPEG") + all_images.append(placeholder_path) + else: + # Use the actual visible slide image + if visible_idx < len(visible_images): + all_images.append(visible_images[visible_idx]) + visible_idx += 1 + + return all_images + + +def create_grids( + image_paths, + cols, + width, + output_path, + placeholder_regions=None, + slide_dimensions=None, +): + """Create multiple thumbnail grids from slide images, max cols×(cols+1) images per grid.""" + # Maximum images per grid is cols × (cols + 1) for better proportions + max_images_per_grid = cols * (cols + 1) + grid_files = [] + + print( + f"Creating grids with {cols} columns (max {max_images_per_grid} images per grid)" + ) + + # Split images into chunks + for chunk_idx, start_idx in enumerate( + range(0, len(image_paths), max_images_per_grid) + ): + end_idx = min(start_idx + max_images_per_grid, len(image_paths)) + chunk_images = image_paths[start_idx:end_idx] + + # Create grid for this chunk + grid = create_grid( + chunk_images, cols, width, start_idx, placeholder_regions, slide_dimensions + ) + + # Generate output filename + if len(image_paths) <= max_images_per_grid: + # Single grid - use base filename without suffix + grid_filename = output_path + else: + # Multiple grids - insert index before extension with dash + stem = output_path.stem + suffix = output_path.suffix + grid_filename = output_path.parent / f"{stem}-{chunk_idx + 1}{suffix}" + + # Save grid + grid_filename.parent.mkdir(parents=True, exist_ok=True) + grid.save(str(grid_filename), quality=JPEG_QUALITY) + grid_files.append(str(grid_filename)) + + return grid_files + + +def create_grid( + image_paths, + cols, + width, + start_slide_num=0, + placeholder_regions=None, + slide_dimensions=None, +): + """Create thumbnail grid from slide images with optional placeholder outlining.""" + font_size = int(width * FONT_SIZE_RATIO) + label_padding = int(font_size * LABEL_PADDING_RATIO) + + # Get dimensions + with Image.open(image_paths[0]) as img: + aspect = img.height / img.width + height = int(width * aspect) + + # Calculate grid size + rows = (len(image_paths) + cols - 1) // cols + grid_w = cols * width + (cols + 1) * GRID_PADDING + grid_h = rows * (height + font_size + label_padding * 2) + (rows + 1) * GRID_PADDING + + # Create grid + grid = Image.new("RGB", (grid_w, grid_h), "white") + draw = ImageDraw.Draw(grid) + + # Load font with size based on thumbnail width + try: + # Use Pillow's default font with size + font = ImageFont.load_default(size=font_size) + except Exception: + # Fall back to basic default font if size parameter not supported + font = ImageFont.load_default() + + # Place thumbnails + for i, img_path in enumerate(image_paths): + row, col = i // cols, i % cols + x = col * width + (col + 1) * GRID_PADDING + y_base = ( + row * (height + font_size + label_padding * 2) + (row + 1) * GRID_PADDING + ) + + # Add label with actual slide number + label = f"{start_slide_num + i}" + bbox = draw.textbbox((0, 0), label, font=font) + text_w = bbox[2] - bbox[0] + draw.text( + (x + (width - text_w) // 2, y_base + label_padding), + label, + fill="black", + font=font, + ) + + # Add thumbnail below label with proportional spacing + y_thumbnail = y_base + label_padding + font_size + label_padding + + with Image.open(img_path) as img: + # Get original dimensions before thumbnail + orig_w, orig_h = img.size + + # Apply placeholder outlines if enabled + if placeholder_regions and (start_slide_num + i) in placeholder_regions: + # Convert to RGBA for transparency support + if img.mode != "RGBA": + img = img.convert("RGBA") + + # Get the regions for this slide + regions = placeholder_regions[start_slide_num + i] + + # Calculate scale factors using actual slide dimensions + if slide_dimensions: + slide_width_inches, slide_height_inches = slide_dimensions + else: + # Fallback: estimate from image size at CONVERSION_DPI + slide_width_inches = orig_w / CONVERSION_DPI + slide_height_inches = orig_h / CONVERSION_DPI + + x_scale = orig_w / slide_width_inches + y_scale = orig_h / slide_height_inches + + # Create a highlight overlay + overlay = Image.new("RGBA", img.size, (255, 255, 255, 0)) + overlay_draw = ImageDraw.Draw(overlay) + + # Highlight each placeholder region + for region in regions: + # Convert from inches to pixels in the original image + px_left = int(region["left"] * x_scale) + px_top = int(region["top"] * y_scale) + px_width = int(region["width"] * x_scale) + px_height = int(region["height"] * y_scale) + + # Draw highlight outline with red color and thick stroke + # Using a bright red outline instead of fill + stroke_width = max( + 5, min(orig_w, orig_h) // 150 + ) # Thicker proportional stroke width + overlay_draw.rectangle( + [(px_left, px_top), (px_left + px_width, px_top + px_height)], + outline=(255, 0, 0, 255), # Bright red, fully opaque + width=stroke_width, + ) + + # Composite the overlay onto the image using alpha blending + img = Image.alpha_composite(img, overlay) + # Convert back to RGB for JPEG saving + img = img.convert("RGB") + + img.thumbnail((width, height), Image.Resampling.LANCZOS) + w, h = img.size + tx = x + (width - w) // 2 + ty = y_thumbnail + (height - h) // 2 + grid.paste(img, (tx, ty)) + + # Add border + if BORDER_WIDTH > 0: + draw.rectangle( + [ + (tx - BORDER_WIDTH, ty - BORDER_WIDTH), + (tx + w + BORDER_WIDTH - 1, ty + h + BORDER_WIDTH - 1), + ], + outline="gray", + width=BORDER_WIDTH, + ) + + return grid + + +if __name__ == "__main__": + main() diff --git a/skills/presentation-master/README.md b/skills/presentation-master/README.md new file mode 100644 index 0000000..12f2f6c --- /dev/null +++ b/skills/presentation-master/README.md @@ -0,0 +1,424 @@ +# Presentation Master + +> **World-class presentation creation skill that embodies best practices from presentation masters and adapts to your needs.** + +## Overview + +Presentation Master is not just a presentation generator—it's a **presentation coach** that teaches world-class design principles while creating slides. Built on decades of wisdom from Garr Reynolds, Nancy Duarte, Guy Kawasaki, Seth Godin, TED speakers, Edward Tufte, and Steve Jobs, this skill ensures every presentation meets the highest standards. + +## Key Innovation + +Instead of just making slides, this skill: +- **Teaches** presentation best practices through guided creation +- **Validates** against proven design principles automatically +- **Adapts** to different presentation types and audiences +- **Coaches** you through checkpoints to ensure quality +- **Learns** from each presentation to improve future recommendations + +## What Makes a Great Presentation? + +Based on research of thousands of successful presentations, the masters agree on these principles: + +1. **Simplicity** - Less is always more (Seth Godin: 6 words max per slide) +2. **Visual Dominance** - Show, don't write (Garr Reynolds: Pictures > text) +3. **Story Structure** - Random facts don't stick; stories do (Nancy Duarte: Sparkline) +4. **One Idea Per Slide** - Cognitive load is real (Guy Kawasaki: 10 slides max) +5. **Audience as Hero** - It's their transformation, not your information (Duarte) +6. **Data Integrity** - Visual truth matters (Edward Tufte: Lie factor 0.95-1.05) + +## Features + +### Guided Creation with Checkpoints + +**Phase 1: Discovery & Context Analysis** +- Analyzes topic, audience, duration, purpose +- Detects presentation type (board update, keynote, training, TED-style) +- Recommends story framework + +**Phase 2: Content Development** +- Researches topic if needed +- Extracts key concepts (max 10 per Kawasaki) +- Drafts slide outline with one concept per slide +- Identifies slides needing visuals + +**Phase 3: Visual Strategy** +- Proposes image types (infographic, photo, diagram, data viz) +- Suggests visual concepts and metaphors +- Estimates generation costs +- Gets approval before generating + +**Phase 4: Generation & Validation** +- Generates approved images in parallel +- Builds slides using selected format (PPTX/Slides/Canva) +- Applies design rules automatically +- Runs validation scoring (0-100) +- Generates quality report + +**Phase 5: Iteration & Refinement** (if needed) +- Applies requested changes +- Re-validates quality +- Saves to Obsidian with metadata +- Documents learnings + +### Automatic Quality Validation + +Every presentation is scored 0-100 against these criteria: + +- **Simplicity** (10pts): Word count, visual clutter +- **Visual Dominance** (10pts): Image quality, text-to-visual ratio +- **Story Structure** (10pts): Narrative arc, emotional beats +- **One Idea/Slide** (10pts): Concept clarity +- **Typography** (8pts): Size (30pt+ minimum), consistency +- **Layout** (7pts): Hierarchy, whitespace, alignment +- **Color/Contrast** (7pts): Readability (4.5:1 minimum) +- **Media Quality** (8pts): Image resolution, relevance +- **Cognitive Load** (20pts): Mayer's 12 multimedia principles +- **Data Integrity** (10pts): Tufte principles (if applicable) + +**Target Score**: 85+ for high-quality presentations + +### Critical Violations (Auto-Fail) + +- Font size < 30pt +- >10 core concepts +- Bullet points detected +- Paragraphs (>2 sentences) +- Poor contrast (<4.5:1) +- Default templates + +### Multi-Format Support + +**Phase 1 (Current)**: PPTX +- Uses existing pptx skill +- Direct PptxGenJS API for simple slides +- Saves to Obsidian Research folder + +**Phase 2 (Coming)**: Google Slides +- Google Slides API v1 +- Supports all 3 accounts (psd, kh, hrg) +- Returns shareable link + +**Phase 3 (Future)**: Canva +- Canva REST API +- Auto-applies brand kits + +## Slide Patterns + +Six proven patterns that form the foundation of world-class presentations: + +### 1. Title Slide +**Purpose**: Set tone, introduce topic +**Elements**: 3-6 words, strong visual or clean typography +**Best for**: Opening, section breaks + +### 2. One Big Idea +**Purpose**: Maximum impact, single concept +**Elements**: 1-3 words max, 60-120pt font +**Best for**: Key insights, memorable moments (Seth Godin's 6-word rule) + +### 3. Visual + Caption +**Purpose**: Visual storytelling with context +**Elements**: Large high-quality image (70-80%), short caption (1 line) +**Best for**: Concepts, examples, emotional moments + +### 4. Data Visualization +**Purpose**: Show quantitative information clearly +**Elements**: Clean charts following Tufte principles +**Best for**: Evidence, trends, comparisons + +### 5. Timeline / Process +**Purpose**: Show progression, sequence, chronology +**Elements**: 3-7 steps, visual connections, minimal text +**Best for**: Processes, roadmaps, historical progression + +### 6. Transition / Section Break +**Purpose**: Signal major shifts +**Elements**: 1-5 words, distinct visual treatment +**Best for**: Moving between major sections + +See `principles/slide-patterns.md` for comprehensive details on each pattern. + +## Story Frameworks + +Choose the right narrative structure for your presentation: + +### Nancy Duarte's Sparkline +**Duration**: 20-30 minutes +**Slides**: 18-25 +**Best for**: Keynotes, vision casting, inspirational talks +**Structure**: Alternate "what is" (reality) with "what could be" (aspiration) + +### Steve Jobs' Rule of Three +**Duration**: 15-30 minutes +**Slides**: 12-18 +**Best for**: Product launches, demos, persuasive presentations +**Structure**: Three main sections, three points per section + +### TED Talk Structure +**Duration**: 15-20 minutes +**Slides**: 12-18 +**Best for**: Idea-centric, inspirational talks +**Structure**: Hook → Personal → Core Idea → Call to Action → Close + +### Classic Three-Act Structure +**Duration**: 20-45 minutes +**Slides**: 15-35 +**Best for**: Case studies, transformation narratives +**Structure**: Setup (25%) → Confrontation (50%) → Resolution (25%) + +See `principles/story-frameworks.md` for detailed breakdowns. + +## Adaptive Pattern Selection + +The skill automatically recommends pattern distribution based on presentation type: + +**Board Update**: 40% Data Viz, 30% Visual+Caption, 20% Transitions, 10% Titles +**Keynote**: 40% Big Ideas, 30% Visual+Caption, 20% Titles, 10% Transitions +**Training**: 40% Process, 30% Data Viz, 20% Visual+Caption, 10% Titles +**Pitch**: 30% Data Viz, 30% Big Ideas, 25% Visual+Caption, 15% Titles/Transitions + +## Image Generation Integration + +Intelligent visual recommendations based on slide content: + +- **Numeric data** → Infographic +- **Abstract concepts** → Conceptual image/metaphor +- **Concrete examples** → Realistic photography +- **Processes/flows** → Diagrams +- **Trends/comparisons** → Data visualization + +**Cost Management**: +- Shows estimated cost before generating ($0.13-$0.24 per image at 2K) +- Allows opt-out of specific images +- Tracks spending in presentation metadata + +**Naming Convention**: +``` +{presentation-id}-slide-{number}-{type}.png +Example: cybersecurity-2025-slide-02-threat-timeline.png +``` + +## Brand Integration + +Automatically applies branding: +- **PSD presentations**: Uses psd-brand-guidelines skill +- **Personal presentations**: Uses personal brand (if defined) +- **Client presentations**: Custom brand kit (future) + +## File Structure + +``` +presentation-master/ +├── SKILL.md # Main skill documentation +├── README.md # This file +├── package.json # Dependencies +├── principles/ +│ ├── masters.md # Best practices from experts (1,200+ lines) +│ ├── validation-rules.md # Quality scoring system +│ ├── slide-patterns.md # Template library (3,500+ lines) +│ └── story-frameworks.md # Narrative structures (5,000+ lines) +├── scripts/ +│ ├── analyze-context.js # ✅ Detect presentation type & recommend framework +│ ├── validate-presentation.js # ✅ Score presentation 0-100 +│ └── suggest-images.js # ✅ Visual recommendations & cost estimation +└── adapters/ + ├── pptx-adapter.js # ✅ PowerPoint translation layer + ├── slides-adapter.js # ✅ Google Slides translation layer + └── canva-adapter.js # (future) Canva integration +``` + +## Usage Examples + +### Example 1: Board Update + +``` +User: "Create presentation on cybersecurity trends for school board, 15 minutes" + +Geoffrey: +**Context Analysis** +- Type: Board/Executive Update +- Audience: School board (non-technical) +- Duration: 15 minutes +- Purpose: Inform + Recommend action + +**Recommended Structure** +Current State → Trends → Implications → Recommendations (10 slides) + +[After approval] + +**Draft Outline** +1. Title: Cybersecurity Trends 2025 +2. Current Threat Landscape [visual: threat timeline] +3. Trend 1: AI-Powered Attacks [visual: concept illustration] +... + +**Visual Strategy** +- 7 images recommended +- Estimated cost: $0.94 (2K resolution) +- Mix: 3 infographics, 2 charts, 1 diagram, 1 illustration + +[After approval and generation] + +**Quality Score: 91/100** +✓ All fonts 36pt+ +✓ Avg 4.2 words/slide +✓ High contrast (8.5:1) +⚠ Slide 8 has 7 words (rec: 6 max) + +Created: /Obsidian/Research/cybersecurity-trends-2025-board.pptx +``` + +### Example 2: Keynote + +``` +User: "Create keynote on future of education for conference, 30 minutes" + +Geoffrey: +**Context Analysis** +- Type: Keynote/TED-style +- Audience: Education professionals + parents +- Duration: 30 minutes +- Purpose: Inspire + Shift perspective + +**Recommended Structures** +1. Sparkline: What is → What could be (12 slides) ⭐ +2. Rule of Three: Past → Present → Future (9 slides) +3. Three-Act: Problem → Trials → New reality (10 slides) + +[Continues with guided creation...] +``` + +## Dependencies + +- `pptxgenjs`: PowerPoint generation library (current Phase 1) +- `image-gen` skill: Visual content generation +- `psd-brand-guidelines` skill: Brand colors/logos +- `research` skill: Content development +- `obsidian-manager` skill: Knowledge storage + +## Installation + +This skill is part of Geoffrey's skill library. No separate installation needed. + +Ensure dependencies are installed: +```bash +cd /Users/hagelk/non-ic-code/geoffrey/skills/presentation-master +bun install +``` + +## Triggers + +Natural language activation: +- "create presentation" +- "make presentation" +- "build presentation" +- "design deck" +- "make slides" +- "create slides" +- "presentation for..." +- "slides for..." + +## Version + +**Current**: 1.2.0 (Phases 1-3 Complete) +- ✅ Phase 1: PPTX support via pptx skill +- ✅ Phase 2: Visual Intelligence (analyze-context, suggest-images, validate-presentation scripts) +- ✅ Phase 3: Google Slides support via google-workspace skill +**Future**: 1.3.0 (Canva integration) + +## Learning & Iteration + +After each presentation, metadata is saved to Obsidian: + +```json +{ + "presentation_id": "cybersecurity-2025-board", + "type": "board-update", + "duration": "15min", + "slides": 10, + "quality_score": 91, + "images_generated": 7, + "generation_cost": 0.94, + "user_edits": ["slide-8-wording"], + "effectiveness": "approved-minor-changes", + "created": "2025-11-24", + "learnings": "Board prefers data charts over concept graphics" +} +``` + +This enables: +- Quality score trending +- Pattern library expansion +- User preference learning +- Cost optimization + +## Philosophy + +**Code Before Prompts** (Geoffrey Principle): +- Deterministic design rules codified in software +- AI orchestrates, doesn't improvise design +- Validation is automatic, not subjective + +**Progressive Disclosure** (Geoffrey Principle): +- Tier 1: Core workflow (always loaded) +- Tier 2: Detailed principles (loaded when skill activates) +- Tier 3: Scripts and data (fetched just-in-time) + +**Checkpoints Are Non-Negotiable**: +- Structure approval before content development +- Outline approval before visual strategy +- Visual approval before generation +- Quality review before finalization + +## References + +**Books**: +- *Presentation Zen* by Garr Reynolds +- *Resonate* by Nancy Duarte +- *slide:ology* by Nancy Duarte +- *The Visual Display of Quantitative Information* by Edward Tufte +- *Multimedia Learning* by Richard Mayer + +**Articles**: +- Guy Kawasaki: The 10/20/30 Rule of PowerPoint +- Seth Godin: Really Bad PowerPoint +- TED: Create + Prepare Slides Guide + +**Principles Documentation**: +- `principles/masters.md` - Comprehensive best practices +- `principles/validation-rules.md` - Quality scoring details +- `principles/slide-patterns.md` - Pattern specifications +- `principles/story-frameworks.md` - Narrative structures + +## Future Enhancements + +**Phase 4: Canva Integration** +- Canva REST API adapter +- Auto-apply brand kits +- Template library integration + +**Phase 5: Advanced Features** +- Auto-generate speaker notes +- Rehearsal timing suggestions +- A/B test different structures +- Effectiveness tracking +- Personal pattern library from successes + +## Contributing + +Improvements welcome! When adding new features: +1. Follow existing architectural patterns +2. Document in appropriate principles file +3. Add examples to SKILL.md +4. Update version in package.json +5. Add learning to metadata tracking + +## License + +MIT License - See LICENSE file for details + +--- + +**Remember**: The best presentations are simple, visual, story-driven, and focused on the audience's transformation—not the speaker's information. + +Built with ❤️ by Geoffrey diff --git a/skills/presentation-master/SKILL.md b/skills/presentation-master/SKILL.md new file mode 100644 index 0000000..cde7661 --- /dev/null +++ b/skills/presentation-master/SKILL.md @@ -0,0 +1,449 @@ +--- +name: presentation-master +description: World-class presentation creation embodying principles from Garr Reynolds, Nancy Duarte, Guy Kawasaki, Seth Godin, and TED +triggers: + - "create presentation" + - "make presentation" + - "build presentation" + - "design deck" + - "make slides" + - "create slides" + - "build deck" + - "presentation for" + - "slides for" +allowed-tools: Read, Write, Bash, WebSearch, Skill, AskUserQuestion +version: 1.0.0 +--- + +# Presentation Master + +World-class presentation creation skill that embodies best practices from presentation masters and adapts to your needs. + +## Philosophy + +**Key Innovation**: This isn't just a presentation generator—it's a presentation *coach* that teaches world-class design while creating slides. + +Principles from: +- **Garr Reynolds** (Presentation Zen) - Simplicity and visual storytelling +- **Nancy Duarte** (Resonate) - Story structure and audience as hero +- **Guy Kawasaki** - 10/20/30 rule (10 slides, 20 minutes, 30pt fonts) +- **Seth Godin** - 6 words maximum per slide +- **TED** - Visual-first, minimal text, high impact +- **Edward Tufte** - Data integrity and information design +- **Steve Jobs** - Rule of Three and surprise moments + +## Workflow: Guided Creation with Checkpoints + +### Phase 1: Discovery & Context Analysis + +**User provides**: Topic + Audience + Duration + +**Skill analyzes**: +- Presentation type (board update, keynote, training, TED-style) +- Audience level (technical, executive, general public) +- Key message and desired transformation +- Story framework recommendation + +**Checkpoint 1**: Present 3 structure options with rationale → user approves + +### Phase 2: Content Development + +**Skill develops**: +- Research topic if needed (web search, Obsidian knowledge) +- Extract maximum 10 core concepts (Kawasaki rule) +- Apply "what is / what could be" alternation (Duarte) +- Draft slide outline with one concept per slide +- Identify slides needing visuals + +**Checkpoint 2**: Present outline + visual plan → user approves + +### Phase 3: Visual Strategy + +**Skill proposes** for each visual slide: +- Image type (infographic, photo, diagram, data visualization) +- Visual concept/metaphor +- Aesthetic direction (colors from brand, style, mood) +- Estimated generation cost ($0.13-$0.24 per image) + +**Checkpoint 3**: Present visual strategy → user approves images to generate + +### Phase 4: Generation & Validation + +**Skill executes**: +1. Generate approved images in parallel using image-gen skill +2. Build slides using selected adapter (PPTX/Google Slides/Canva) +3. Apply design rules automatically: + - 30pt+ fonts minimum + - <6 words per slide (Godin standard) + - High contrast (4.5:1 minimum) + - No bullet points + - No paragraphs +4. Run validation scoring (0-100 scale) +5. Generate quality report + +**Checkpoint 4**: Present presentation + quality report → user reviews + +### Phase 5: Iteration & Refinement (if needed) + +**Skill refines**: +- Apply requested changes +- Re-validate quality score +- Save final presentation to Obsidian Research folder +- Document learnings and metadata + +## Validation Scoring (0-100) + +### CRITICAL Violations (Auto-fail) +- Font size < 30pt +- >10 core concepts +- Bullet points detected +- Paragraphs (>2 consecutive sentences) +- Poor contrast ratio (<4.5:1) +- Default template usage + +### WARNING Flags +- >6 words per slide +- >15 slides for 20-min presentation +- No images in presentation +- Text-heavy slides (>3 lines) +- Inconsistent fonts (>2 families) +- Low-resolution images + +### Quality Score Breakdown +- **Simplicity** (10pts): Word count, visual clutter +- **Visual Dominance** (10pts): Image quality, text-to-visual ratio +- **Story Structure** (10pts): Narrative arc, emotional beats +- **One Idea/Slide** (10pts): Concept clarity +- **Typography** (8pts): Size, consistency +- **Layout** (7pts): Hierarchy, whitespace, alignment +- **Color/Contrast** (7pts): Readability, brand consistency +- **Media Quality** (8pts): Image resolution, relevance +- **Cognitive Load** (20pts): Mayer's 12 multimedia principles +- **Data Integrity** (10pts): Tufte principles (if data present) + +**Target Score**: 85+ for high-quality presentations + +## Slide Pattern Library + +### Six Core Patterns + +1. **Title Slide** - Minimal text, strong visual, sets tone +2. **One Big Idea** - Single word/number/image, max 6 words +3. **Visual + Caption** - Large high-quality image, short caption +4. **Data Visualization** - Charts following Tufte principles (maximize data-ink ratio) +5. **Timeline/Process** - Linear flow, minimal text per step +6. **Transition/Section Break** - Single word or phrase, signals shift + +### Adaptive Pattern Selection + +**Board/Executive Update**: Patterns 3, 4, 6 (data-focused, professional) +**Keynote/TED-style**: Patterns 1, 2, 3 (story-focused, visual-first) +**Training/Education**: Patterns 4, 5 (process-focused, clarity) +**Pitch/Demo**: Patterns 2, 3, 4 (impact-focused, evidence-based) + +## Story Frameworks + +### Nancy Duarte's Sparkline +- Alternate "what is" (current reality) with "what could be" (aspiration) +- Build tension through contrast between present and future +- End with transformation and new reality + +### The Rule of Three (Steve Jobs) +- Break presentation into 3 main sections +- 3 key features/points per section +- Memorable and dramatic + +### TED Structure +- Hook (first 30 seconds) - Grab attention +- Personal connection - Why this matters to you +- Core idea with evidence - The meat +- Call to action - What next +- Strong close - Never end with Q&A + +## Output Format Support + +### Current: PPTX (Phase 1) +- Uses existing pptx skill +- Direct PptxGenJS API for simple slides +- html2pptx.js for complex layouts +- Saves to Obsidian Research folder +- Generates quality validation report + +### Coming: Google Slides (Phase 2) +- Google Slides API v1 +- Integrates with google-workspace skill +- Supports all 3 accounts (psd, kh, hrg) +- Returns shareable link + +### Future: Canva (Phase 3) +- Canva REST API +- Auto-apply brand kits +- Returns shareable link + +## Image Generation Integration + +### Intelligent Visual Recommendations + +For each slide, analyzes: +- **Numeric data** → Infographic recommendation +- **Abstract concepts** → Conceptual image/metaphor (especially for keynotes) +- **Concrete examples** → Photo/realistic imagery +- **Processes/flows** → Diagram recommendation +- **Trends/comparisons** → Chart/data visualization + +### Prompt Generation (6-Step Process) + +From image-gen skill: +1. Extract narrative from slide content +2. Choose visual concept/metaphor +3. Apply aesthetic (brand colors, presentation style) +4. Construct detailed prompt +5. Execute generation +6. Validate output + +### Cost Management +- Show total estimated cost before generating +- Allow opt-out of specific images +- Cache generated images for reuse +- Track spending in presentation metadata + +### Naming Convention +``` +{presentation-id}-slide-{number}-{type}.png + +Examples: +cybersecurity-2025-slide-02-threat-timeline.png +port-ai-2025-slide-04-breakthroughs.png +``` + +## Brand Integration + +Automatically detects and applies branding: +- **PSD presentations**: Use psd-brand-guidelines skill (Sea Glass, Pacific, etc.) +- **Personal presentations**: Use personal brand (if defined) +- **Client presentations**: Custom brand kit (future) + +Applies to: +- Color palettes +- Typography choices +- Logo placement +- Overall aesthetic + +## Learning & Metadata Tracking + +After each presentation, save metadata to Obsidian: + +```json +{ + "presentation_id": "cybersecurity-2025-board", + "type": "board-update", + "audience": "school-board", + "duration": "15min", + "slides": 10, + "quality_score": 91, + "images_generated": 7, + "generation_cost": 0.94, + "validation_warnings": 1, + "user_edits": ["slide-8-wording"], + "effectiveness": "approved-minor-changes", + "created": "2025-11-24", + "tools_used": ["research", "image-gen", "pptx"], + "learnings": "Board prefers data charts over concept graphics" +} +``` + +## Integration with Existing Skills + +**Dependencies**: +- `image-gen` - Visual content generation +- `pptx` - PowerPoint creation (Phase 1) +- `google-workspace` - Google Slides (Phase 2) +- `psd-brand-guidelines` - Brand colors/logos +- `research` - Content development +- `obsidian-manager` - Knowledge storage + +**Coordination Pattern**: +``` +presentation-master (orchestrator) +├── calls research for content depth +├── calls image-gen for visuals +├── calls pptx/slides/canva adapter for output +├── calls psd-brand-guidelines for colors/logos +└── calls obsidian-manager to save final + metadata +``` + +## Usage Examples + +### Example 1: Board Update +``` +User: "Create presentation on cybersecurity trends for school board, 15 minutes" + +Geoffrey: I'll create a board update presentation on cybersecurity trends. + +**Context Analysis** +- Type: Board/Executive Update +- Audience: School board (non-technical) +- Duration: 15 minutes +- Purpose: Inform + Recommend action + +**Recommended Structures** +1. Problem → Solution → Action (8 slides) +2. Current State → Trends → Implications → Recommendations (10 slides) ⭐ +3. Story: Recent incident → Broader context → Our response (7 slides) + +Which structure resonates? + +[User selects #2] + +**Draft Outline** (10 slides, one concept each) +1. Title: Cybersecurity Trends 2025 +2. Current Threat Landscape [visual: threat timeline] +3. Trend 1: AI-Powered Attacks [visual: concept illustration] +4. Trend 2: Ransomware Evolution [visual: data chart] +5. Trend 3: Supply Chain Risks [visual: network diagram] +6. Impact on Education Sector [visual: stat infographic] +7. Our Current Posture [visual: assessment chart] +8. Gaps & Vulnerabilities [text-focused, high contrast] +9. Recommended Actions [visual: roadmap] +10. Investment & Timeline [visual: budget chart] + +**Visual Strategy** +- 7 images recommended +- Estimated cost: $0.94 (2K resolution) +- Mix: 3 infographics, 2 charts, 1 diagram, 1 illustration + +Approve and proceed? + +[User approves] + +Generating 7 visuals in parallel... +✓ All generated (0.94 total) + +Building presentation with PSD brand colors... +Validating against best practices... + +**Quality Score: 91/100** +✓ All fonts 36pt+ +✓ Avg 4.2 words/slide +✓ High contrast (8.5:1) +✓ Story arc present +✓ Cognitive load optimized +⚠ Slide 8 has 7 words (rec: 6 max) + +Created: /Obsidian/Research/cybersecurity-trends-2025-board.pptx +``` + +### Example 2: Keynote +``` +User: "Create keynote on future of education for conference, 30 minutes" + +Geoffrey: I'll create a TED-style keynote on the future of education. + +**Context Analysis** +- Type: Keynote/TED-style +- Audience: Education professionals + parents +- Duration: 30 minutes +- Purpose: Inspire + Shift perspective + +**Recommended Structures** (Nancy Duarte's Sparkline) +1. What education is today → What it could be → Transformation (12 slides) ⭐ +2. Steve Jobs Rule of Three: Past → Present → Future (9 slides) +3. Hero's Journey: Problem → Trials → New reality (10 slides) + +Which framework? + +[Continues with guided creation...] +``` + +## Quality Checklist + +Before presenting to user, verify: + +**Content** +- [ ] One main idea per slide +- [ ] Clear story arc (beginning/middle/end) +- [ ] Audience positioned as hero +- [ ] Emotional connection established +- [ ] Maximum 10 core concepts + +**Design** +- [ ] All fonts 30pt+ minimum +- [ ] High contrast (4.5:1+) +- [ ] No bullet points +- [ ] No paragraphs +- [ ] Maximum 6 words per slide (or justified exception) +- [ ] All images high-resolution +- [ ] Consistent fonts/colors/alignment +- [ ] No transitions or animations + +**Data Visualization** (if applicable) +- [ ] Lie factor 0.95-1.05 +- [ ] Maximum data-ink ratio +- [ ] Clear, detailed labeling +- [ ] No chart junk (3D effects, unnecessary borders) + +**Structure** +- [ ] Follows chosen framework (Duarte/Jobs/TED) +- [ ] Creates tension and resolution +- [ ] Includes surprise/memorable moments +- [ ] Ends strong (not with Q&A) +- [ ] Appropriate length for time + +## Advanced Features + +### Context Detection + +Automatically infers presentation type from cues: +- "board meeting" → Board update (data-focused) +- "keynote" or "conference" → Keynote (story-focused) +- "training" or "workshop" → Educational (process-focused) +- "pitch" or "investor" → Pitch (evidence-focused) + +### Smart Defaults + +Based on detected type: +- **Board update**: 10 slides, 8 with visuals, professional tone +- **Keynote**: 12-15 slides, minimal text, emotional arc +- **Training**: 15-20 slides, process diagrams, step-by-step +- **Pitch**: 10 slides (Kawasaki rule), data-driven, ROI focus + +### Accessibility + +Ensures presentations are accessible: +- High contrast text (4.5:1 minimum, aim for 7:1) +- Large fonts (30pt minimum, 36pt+ preferred) +- Clear hierarchy and flow +- Alt text for images (future enhancement) + +## Limitations & Future Enhancements + +**Current Limitations**: +- No animation support (by design - Godin principle) +- No video embedding yet (future enhancement) +- No speaker notes generation (Phase 2) +- No slide master editing (uses templates) + +**Future Enhancements**: +- Auto-generate speaker notes from slide content +- Suggest rehearsal timing +- A/B test different structures +- Track presentation effectiveness scores +- Build personal pattern library from successful presentations + +## References + +Full principles documentation in: +- `principles/masters.md` - Expert best practices +- `principles/validation-rules.md` - Quality scoring system +- `principles/slide-patterns.md` - Template library +- `principles/story-frameworks.md` - Narrative structures + +Scripts and adapters: +- `scripts/analyze-context.js` - Type detection +- `adapters/pptx-adapter.js` - PowerPoint output +- `adapters/slides-adapter.js` - Google Slides (Phase 2) +- `adapters/canva-adapter.js` - Canva (Phase 3) + +--- + +**Remember**: The best presentations are simple, visual, story-driven, and focused on the audience's transformation—not the speaker's information. diff --git a/skills/presentation-master/adapters/pptx-adapter.js b/skills/presentation-master/adapters/pptx-adapter.js new file mode 100644 index 0000000..952cc03 --- /dev/null +++ b/skills/presentation-master/adapters/pptx-adapter.js @@ -0,0 +1,397 @@ +#!/usr/bin/env bun + +/** + * PPTX Adapter + * + * Converts presentation specification to PPTX format specification. + * Integrates with pptx skill for actual file generation. + * + * Usage: + * bun pptx-adapter.js --presentation presentation.json --output pptx-spec.json + * + * Output: PPTX specification that pptx skill can execute + */ + +// PSD Brand Colors +const PSD_COLORS = { + primary_teal: '6CA18A', + dark_blue: '25424C', + cream: 'FFFAEC', + warm_gray: 'EEEBE4', + black: '000000', + white: 'FFFFFF' +}; + +/** + * Generate PPTX specification from presentation + */ +function generatePptxSpec(presentation, options = {}) { + const brand = options.brand || null; + const outputPath = options.output_path || null; + + const spec = { + title: presentation.title, + author: options.author || 'Geoffrey', + subject: presentation.description || presentation.title, + layout: '16x9', + output_path: outputPath, + slides: [] + }; + + // Apply default theme if brand specified + if (brand === 'psd') { + spec.theme = { + background: PSD_COLORS.warm_gray, + primary_color: PSD_COLORS.primary_teal, + secondary_color: PSD_COLORS.dark_blue, + text_color: PSD_COLORS.black, + accent_color: PSD_COLORS.cream + }; + } + + // Convert slides + for (const slide of presentation.slides) { + const slideSpec = convertSlide(slide, brand); + spec.slides.push(slideSpec); + } + + return spec; +} + +/** + * Convert individual slide based on pattern + */ +function convertSlide(slide, brand) { + switch (slide.pattern) { + case 'title': + return convertTitleSlide(slide, brand); + + case 'big-idea': + return convertBigIdeaSlide(slide, brand); + + case 'visual-caption': + return convertVisualCaptionSlide(slide, brand); + + case 'data-viz': + return convertDataVizSlide(slide, brand); + + case 'process': + case 'timeline': + return convertProcessSlide(slide, brand); + + case 'transition': + return convertTransitionSlide(slide, brand); + + default: + return convertDefaultSlide(slide, brand); + } +} + +/** + * Title Slide + */ +function convertTitleSlide(slide, brand) { + const spec = { + type: 'title', + background: brand === 'psd' ? PSD_COLORS.dark_blue : 'FFFFFF', + elements: [] + }; + + // Title + spec.elements.push({ + type: 'text', + text: slide.title, + x: '10%', + y: '35%', + w: '80%', + h: '30%', + fontSize: 48, + bold: true, + color: brand === 'psd' ? PSD_COLORS.cream : '000000', + align: 'center', + valign: 'middle', + fontFace: 'Arial' + }); + + // Subtitle if present + if (slide.text) { + spec.elements.push({ + type: 'text', + text: slide.text, + x: '15%', + y: '65%', + w: '70%', + h: '10%', + fontSize: 24, + color: brand === 'psd' ? PSD_COLORS.cream : '666666', + align: 'center', + fontFace: 'Arial' + }); + } + + return spec; +} + +/** + * Big Idea Slide + */ +function convertBigIdeaSlide(slide, brand) { + // Calculate font size based on text length + const textLength = slide.title.length; + const fontSize = Math.min(120, Math.max(60, Math.floor(300 / textLength))); + + const spec = { + type: 'big-idea', + background: 'FFFFFF', + elements: [{ + type: 'text', + text: slide.title, + x: '10%', + y: '25%', + w: '80%', + h: '50%', + fontSize, + bold: true, + color: brand === 'psd' ? PSD_COLORS.primary_teal : '000000', + align: 'center', + valign: 'middle', + fontFace: 'Arial' + }] + }; + + return spec; +} + +/** + * Visual + Caption Slide + */ +function convertVisualCaptionSlide(slide, brand) { + const spec = { + type: 'visual-caption', + background: brand === 'psd' ? PSD_COLORS.warm_gray : 'FFFFFF', + elements: [] + }; + + // Image (70-80% of slide) + if (slide.image) { + spec.elements.push({ + type: 'image', + path: slide.image.url || slide.image.path, + x: '5%', + y: '5%', + w: '90%', + h: '70%', + sizing: { + type: 'contain', + w: '90%', + h: '70%' + } + }); + } + + // Caption (bottom) + spec.elements.push({ + type: 'text', + text: slide.text || slide.title, + x: '5%', + y: '80%', + w: '90%', + h: '15%', + fontSize: 24, + color: '000000', + align: 'center', + valign: 'top', + fontFace: 'Arial' + }); + + return spec; +} + +/** + * Data Visualization Slide + */ +function convertDataVizSlide(slide, brand) { + const spec = { + type: 'data-viz', + background: brand === 'psd' ? PSD_COLORS.warm_gray : 'FFFFFF', + elements: [] + }; + + // Header bar if PSD brand + if (brand === 'psd') { + spec.elements.push({ + type: 'rect', + x: 0, + y: 0, + w: '100%', + h: '12%', + fill: { color: PSD_COLORS.dark_blue } + }); + + spec.elements.push({ + type: 'text', + text: slide.title, + x: '5%', + y: '1%', + w: '90%', + h: '10%', + fontSize: 36, + bold: true, + color: PSD_COLORS.cream, + fontFace: 'Arial' + }); + } else { + spec.elements.push({ + type: 'text', + text: slide.title, + x: '5%', + y: '5%', + w: '90%', + h: '10%', + fontSize: 36, + bold: true, + color: '000000', + fontFace: 'Arial' + }); + } + + // Chart/Data visualization + if (slide.chart || slide.image) { + const yOffset = brand === 'psd' ? '18%' : '18%'; + spec.elements.push({ + type: 'image', + path: (slide.chart || slide.image).url || (slide.chart || slide.image).path, + x: '7.5%', + y: yOffset, + w: '85%', + h: '70%', + sizing: { + type: 'contain', + w: '85%', + h: '70%' + } + }); + } + + return spec; +} + +/** + * Process/Timeline Slide + */ +function convertProcessSlide(slide, brand) { + const spec = { + type: 'process', + background: brand === 'psd' ? PSD_COLORS.warm_gray : 'FFFFFF', + elements: [] + }; + + // Title + spec.elements.push({ + type: 'text', + text: slide.title, + x: '5%', + y: '5%', + w: '90%', + h: '12%', + fontSize: 36, + bold: true, + color: brand === 'psd' ? PSD_COLORS.dark_blue : '000000', + fontFace: 'Arial' + }); + + // Process diagram + if (slide.image) { + spec.elements.push({ + type: 'image', + path: slide.image.url || slide.image.path, + x: '5%', + y: '25%', + w: '90%', + h: '65%', + sizing: { + type: 'contain', + w: '90%', + h: '65%' + } + }); + } + + return spec; +} + +/** + * Transition Slide + */ +function convertTransitionSlide(slide, brand) { + const spec = { + type: 'transition', + background: 'FFFFFF', + elements: [{ + type: 'text', + text: slide.title, + x: '10%', + y: '35%', + w: '80%', + h: '30%', + fontSize: 42, + bold: true, + color: brand === 'psd' ? PSD_COLORS.primary_teal : '000000', + align: 'center', + valign: 'middle', + fontFace: 'Arial' + }] + }; + + return spec; +} + +/** + * Default Slide (fallback) + */ +function convertDefaultSlide(slide, brand) { + return convertTitleSlide(slide, brand); +} + +// CLI Interface +function main() { + const args = {}; + + for (let i = 2; i < process.argv.length; i++) { + if (process.argv[i].startsWith('--')) { + const key = process.argv[i].replace(/^--/, ''); + const value = process.argv[i + 1]; + args[key] = value; + i++; + } + } + + if (!args.presentation) { + console.error('Usage: bun pptx-adapter.js --presentation presentation.json [--brand psd] [--output pptx-spec.json]'); + process.exit(1); + } + + const fs = require('fs'); + const presentation = JSON.parse(fs.readFileSync(args.presentation, 'utf-8')); + + const options = { + brand: args.brand || null, + output_path: args['output-path'] || null, + author: args.author || 'Geoffrey' + }; + + const pptxSpec = generatePptxSpec(presentation, options); + + if (args.output) { + fs.writeFileSync(args.output, JSON.stringify(pptxSpec, null, 2)); + console.log(`PPTX specification written to ${args.output}`); + } else { + console.log(JSON.stringify(pptxSpec, null, 2)); + } +} + +if (import.meta.main) { + main(); +} + +export { generatePptxSpec, convertSlide }; diff --git a/skills/presentation-master/adapters/slides-adapter.js b/skills/presentation-master/adapters/slides-adapter.js new file mode 100644 index 0000000..ce4802e --- /dev/null +++ b/skills/presentation-master/adapters/slides-adapter.js @@ -0,0 +1,794 @@ +#!/usr/bin/env bun + +/** + * Google Slides Adapter + * + * Converts presentation specification to Google Slides API requests. + * Integrates with google-workspace skill for authentication and API access. + * + * Usage: + * bun slides-adapter.js --presentation presentation.json --account psd --output slides-spec.json + * + * Output: Google Slides API request specification that google-workspace skill can execute + */ + +// PSD Brand Colors (from psd-brand-guidelines skill) +const PSD_COLORS = { + primary_teal: '#6CA18A', + dark_blue: '#25424C', + cream: '#FFFAEC', + warm_gray: '#EEEBE4', + black: '#000000', + white: '#FFFFFF' +}; + +// Slide dimensions (16:9 aspect ratio) +const SLIDE_DIMENSIONS = { + width: { magnitude: 10, unit: 'INCHES' }, + height: { magnitude: 5.625, unit: 'INCHES' } +}; + +// Convert points to EMU (English Metric Units) for Google Slides API +function pointsToEmu(points) { + return Math.round(points * 12700); +} + +// Convert inches to EMU +function inchesToEmu(inches) { + return Math.round(inches * 914400); +} + +/** + * Generate Google Slides API requests for creating a presentation + */ +function generateSlidesRequests(presentation, options = {}) { + const account = options.account || 'psd'; + const applyBrand = options.brand !== false; + + const requests = []; + + // 1. Create presentation + const createRequest = { + operation: 'create_presentation', + params: { + title: presentation.title, + locale: 'en-US' + } + }; + + // 2. Delete default slide + const deleteDefaultSlide = { + operation: 'delete_object', + params: { + objectId: '{{DEFAULT_SLIDE_ID}}' // Will be replaced after creation + } + }; + + // 3. Apply master theme if PSD brand + let masterThemeRequests = []; + if (applyBrand && account === 'psd') { + masterThemeRequests = generatePsdTheme(); + } + + // 4. Create slides + const slideRequests = []; + for (let i = 0; i < presentation.slides.length; i++) { + const slide = presentation.slides[i]; + const slideId = `slide_${i}`; + + // Create slide + slideRequests.push({ + operation: 'create_slide', + params: { + objectId: slideId, + insertionIndex: i, + slideLayoutReference: { predefinedLayout: 'BLANK' } + } + }); + + // Add slide content based on pattern + const contentRequests = generateSlideContent(slide, slideId, applyBrand ? account : null); + slideRequests.push(...contentRequests); + } + + return { + account, + presentation_title: presentation.title, + requests: [ + createRequest, + ...masterThemeRequests, + ...slideRequests + ], + post_creation_steps: [ + 'Delete default slide if present', + 'Return shareable link with edit permissions' + ] + }; +} + +/** + * Generate PSD brand theme + */ +function generatePsdTheme() { + return [ + { + operation: 'update_page_properties', + params: { + objectId: '{{MASTER_SLIDE_ID}}', + pageProperties: { + pageBackgroundFill: { + solidFill: { + color: { rgbColor: hexToRgb(PSD_COLORS.warm_gray) } + } + } + } + } + } + ]; +} + +/** + * Generate slide content based on pattern + */ +function generateSlideContent(slide, slideId, brand) { + const requests = []; + + switch (slide.pattern) { + case 'title': + requests.push(...generateTitleSlide(slide, slideId, brand)); + break; + + case 'big-idea': + requests.push(...generateBigIdeaSlide(slide, slideId, brand)); + break; + + case 'visual-caption': + requests.push(...generateVisualCaptionSlide(slide, slideId, brand)); + break; + + case 'data-viz': + requests.push(...generateDataVizSlide(slide, slideId, brand)); + break; + + case 'process': + case 'timeline': + requests.push(...generateProcessSlide(slide, slideId, brand)); + break; + + case 'transition': + requests.push(...generateTransitionSlide(slide, slideId, brand)); + break; + + default: + requests.push(...generateDefaultSlide(slide, slideId, brand)); + } + + return requests; +} + +/** + * Title Slide Pattern + */ +function generateTitleSlide(slide, slideId, brand) { + const requests = []; + + if (brand === 'psd') { + // Background + requests.push({ + operation: 'update_page_properties', + params: { + objectId: slideId, + pageProperties: { + pageBackgroundFill: { + solidFill: { + color: { rgbColor: hexToRgb(PSD_COLORS.dark_blue) } + } + } + } + } + }); + } + + // Title text + const titleBoxId = `${slideId}_title`; + requests.push({ + operation: 'create_shape', + params: { + objectId: titleBoxId, + shapeType: 'TEXT_BOX', + elementProperties: { + pageObjectId: slideId, + size: { + width: { magnitude: 8, unit: 'INCHES' }, + height: { magnitude: 2, unit: 'INCHES' } + }, + transform: { + scaleX: 1, + scaleY: 1, + translateX: inchesToEmu(1), + translateY: inchesToEmu(1.8), + unit: 'EMU' + } + } + } + }); + + // Insert title text + requests.push({ + operation: 'insert_text', + params: { + objectId: titleBoxId, + text: slide.title, + insertionIndex: 0 + } + }); + + // Style title text + requests.push({ + operation: 'update_text_style', + params: { + objectId: titleBoxId, + textRange: { type: 'ALL' }, + style: { + fontFamily: 'Arial', + fontSize: { magnitude: 48, unit: 'PT' }, + bold: true, + foregroundColor: { + opaqueColor: { + rgbColor: brand === 'psd' + ? hexToRgb(PSD_COLORS.cream) + : hexToRgb('#FFFFFF') + } + } + }, + fields: 'fontFamily,fontSize,bold,foregroundColor' + } + }); + + // Center align + requests.push({ + operation: 'update_paragraph_style', + params: { + objectId: titleBoxId, + textRange: { type: 'ALL' }, + style: { + alignment: 'CENTER' + }, + fields: 'alignment' + } + }); + + return requests; +} + +/** + * Big Idea Slide Pattern + */ +function generateBigIdeaSlide(slide, slideId, brand) { + const requests = []; + + // Massive text in center + const textBoxId = `${slideId}_bigidea`; + requests.push({ + operation: 'create_shape', + params: { + objectId: textBoxId, + shapeType: 'TEXT_BOX', + elementProperties: { + pageObjectId: slideId, + size: { + width: { magnitude: 8, unit: 'INCHES' }, + height: { magnitude: 3, unit: 'INCHES' } + }, + transform: { + scaleX: 1, + scaleY: 1, + translateX: inchesToEmu(1), + translateY: inchesToEmu(1.3), + unit: 'EMU' + } + } + } + }); + + requests.push({ + operation: 'insert_text', + params: { + objectId: textBoxId, + text: slide.title, + insertionIndex: 0 + } + }); + + // Giant font size (60-120pt) + const fontSize = Math.min(120, Math.max(60, Math.floor(300 / slide.title.length))); + + requests.push({ + operation: 'update_text_style', + params: { + objectId: textBoxId, + textRange: { type: 'ALL' }, + style: { + fontFamily: 'Arial', + fontSize: { magnitude: fontSize, unit: 'PT' }, + bold: true, + foregroundColor: { + opaqueColor: { + rgbColor: brand === 'psd' + ? hexToRgb(PSD_COLORS.primary_teal) + : hexToRgb('#000000') + } + } + }, + fields: 'fontFamily,fontSize,bold,foregroundColor' + } + }); + + requests.push({ + operation: 'update_paragraph_style', + params: { + objectId: textBoxId, + textRange: { type: 'ALL' }, + style: { + alignment: 'CENTER' + }, + fields: 'alignment' + } + }); + + return requests; +} + +/** + * Visual + Caption Slide Pattern + */ +function generateVisualCaptionSlide(slide, slideId, brand) { + const requests = []; + + // Image (70-80% of slide) + if (slide.image) { + const imageId = `${slideId}_image`; + requests.push({ + operation: 'create_image', + params: { + objectId: imageId, + url: slide.image.url, + elementProperties: { + pageObjectId: slideId, + size: { + width: { magnitude: 9, unit: 'INCHES' }, + height: { magnitude: 4, unit: 'INCHES' } + }, + transform: { + scaleX: 1, + scaleY: 1, + translateX: inchesToEmu(0.5), + translateY: inchesToEmu(0.3), + unit: 'EMU' + } + } + } + }); + } + + // Caption (1 line, bottom) + const captionId = `${slideId}_caption`; + requests.push({ + operation: 'create_shape', + params: { + objectId: captionId, + shapeType: 'TEXT_BOX', + elementProperties: { + pageObjectId: slideId, + size: { + width: { magnitude: 9, unit: 'INCHES' }, + height: { magnitude: 0.8, unit: 'INCHES' } + }, + transform: { + scaleX: 1, + scaleY: 1, + translateX: inchesToEmu(0.5), + translateY: inchesToEmu(4.6), + unit: 'EMU' + } + } + } + }); + + requests.push({ + operation: 'insert_text', + params: { + objectId: captionId, + text: slide.text || slide.title, + insertionIndex: 0 + } + }); + + requests.push({ + operation: 'update_text_style', + params: { + objectId: captionId, + textRange: { type: 'ALL' }, + style: { + fontFamily: 'Arial', + fontSize: { magnitude: 24, unit: 'PT' }, + foregroundColor: { + opaqueColor: { + rgbColor: hexToRgb('#000000') + } + } + }, + fields: 'fontFamily,fontSize,foregroundColor' + } + }); + + requests.push({ + operation: 'update_paragraph_style', + params: { + objectId: captionId, + textRange: { type: 'ALL' }, + style: { + alignment: 'CENTER' + }, + fields: 'alignment' + } + }); + + return requests; +} + +/** + * Data Visualization Slide Pattern + */ +function generateDataVizSlide(slide, slideId, brand) { + const requests = []; + + // Header + if (brand === 'psd') { + const headerId = `${slideId}_header`; + requests.push({ + operation: 'create_shape', + params: { + objectId: headerId, + shapeType: 'RECTANGLE', + elementProperties: { + pageObjectId: slideId, + size: { + width: { magnitude: 10, unit: 'INCHES' }, + height: { magnitude: 0.8, unit: 'INCHES' } + }, + transform: { + scaleX: 1, + scaleY: 1, + translateX: 0, + translateY: 0, + unit: 'EMU' + } + } + } + }); + + requests.push({ + operation: 'update_shape_properties', + params: { + objectId: headerId, + shapeProperties: { + shapeBackgroundFill: { + solidFill: { + color: { rgbColor: hexToRgb(PSD_COLORS.dark_blue) } + } + } + }, + fields: 'shapeBackgroundFill' + } + }); + + // Header text + const headerTextId = `${slideId}_header_text`; + requests.push({ + operation: 'create_shape', + params: { + objectId: headerTextId, + shapeType: 'TEXT_BOX', + elementProperties: { + pageObjectId: slideId, + size: { + width: { magnitude: 9, unit: 'INCHES' }, + height: { magnitude: 0.6, unit: 'INCHES' } + }, + transform: { + scaleX: 1, + scaleY: 1, + translateX: inchesToEmu(0.5), + translateY: inchesToEmu(0.1), + unit: 'EMU' + } + } + } + }); + + requests.push({ + operation: 'insert_text', + params: { + objectId: headerTextId, + text: slide.title, + insertionIndex: 0 + } + }); + + requests.push({ + operation: 'update_text_style', + params: { + objectId: headerTextId, + textRange: { type: 'ALL' }, + style: { + fontFamily: 'Arial', + fontSize: { magnitude: 36, unit: 'PT' }, + bold: true, + foregroundColor: { + opaqueColor: { + rgbColor: hexToRgb(PSD_COLORS.cream) + } + } + }, + fields: 'fontFamily,fontSize,bold,foregroundColor' + } + }); + } + + // Chart/Image placeholder + if (slide.chart || slide.image) { + const chartId = `${slideId}_chart`; + const yOffset = brand === 'psd' ? 1.0 : 0.5; + + requests.push({ + operation: 'create_image', + params: { + objectId: chartId, + url: (slide.chart || slide.image).url, + elementProperties: { + pageObjectId: slideId, + size: { + width: { magnitude: 8.5, unit: 'INCHES' }, + height: { magnitude: 4, unit: 'INCHES' } + }, + transform: { + scaleX: 1, + scaleY: 1, + translateX: inchesToEmu(0.75), + translateY: inchesToEmu(yOffset), + unit: 'EMU' + } + } + } + }); + } + + return requests; +} + +/** + * Process/Timeline Slide Pattern + */ +function generateProcessSlide(slide, slideId, brand) { + const requests = []; + + // Title + const titleId = `${slideId}_title`; + requests.push({ + operation: 'create_shape', + params: { + objectId: titleId, + shapeType: 'TEXT_BOX', + elementProperties: { + pageObjectId: slideId, + size: { + width: { magnitude: 9, unit: 'INCHES' }, + height: { magnitude: 0.8, unit: 'INCHES' } + }, + transform: { + scaleX: 1, + scaleY: 1, + translateX: inchesToEmu(0.5), + translateY: inchesToEmu(0.3), + unit: 'EMU' + } + } + } + }); + + requests.push({ + operation: 'insert_text', + params: { + objectId: titleId, + text: slide.title, + insertionIndex: 0 + } + }); + + requests.push({ + operation: 'update_text_style', + params: { + objectId: titleId, + textRange: { type: 'ALL' }, + style: { + fontFamily: 'Arial', + fontSize: { magnitude: 36, unit: 'PT' }, + bold: true, + foregroundColor: { + opaqueColor: { + rgbColor: brand === 'psd' + ? hexToRgb(PSD_COLORS.dark_blue) + : hexToRgb('#000000') + } + } + }, + fields: 'fontFamily,fontSize,bold,foregroundColor' + } + }); + + // Process diagram/image + if (slide.image) { + const imageId = `${slideId}_process`; + requests.push({ + operation: 'create_image', + params: { + objectId: imageId, + url: slide.image.url, + elementProperties: { + pageObjectId: slideId, + size: { + width: { magnitude: 9, unit: 'INCHES' }, + height: { magnitude: 3.5, unit: 'INCHES' } + }, + transform: { + scaleX: 1, + scaleY: 1, + translateX: inchesToEmu(0.5), + translateY: inchesToEmu(1.5), + unit: 'EMU' + } + } + } + }); + } + + return requests; +} + +/** + * Transition Slide Pattern + */ +function generateTransitionSlide(slide, slideId, brand) { + const requests = []; + + // Simple centered text + const textId = `${slideId}_transition`; + requests.push({ + operation: 'create_shape', + params: { + objectId: textId, + shapeType: 'TEXT_BOX', + elementProperties: { + pageObjectId: slideId, + size: { + width: { magnitude: 8, unit: 'INCHES' }, + height: { magnitude: 2, unit: 'INCHES' } + }, + transform: { + scaleX: 1, + scaleY: 1, + translateX: inchesToEmu(1), + translateY: inchesToEmu(1.8), + unit: 'EMU' + } + } + } + }); + + requests.push({ + operation: 'insert_text', + params: { + objectId: textId, + text: slide.title, + insertionIndex: 0 + } + }); + + requests.push({ + operation: 'update_text_style', + params: { + objectId: textId, + textRange: { type: 'ALL' }, + style: { + fontFamily: 'Arial', + fontSize: { magnitude: 42, unit: 'PT' }, + bold: true, + foregroundColor: { + opaqueColor: { + rgbColor: brand === 'psd' + ? hexToRgb(PSD_COLORS.primary_teal) + : hexToRgb('#000000') + } + } + }, + fields: 'fontFamily,fontSize,bold,foregroundColor' + } + }); + + requests.push({ + operation: 'update_paragraph_style', + params: { + objectId: textId, + textRange: { type: 'ALL' }, + style: { + alignment: 'CENTER' + }, + fields: 'alignment' + } + }); + + return requests; +} + +/** + * Default Slide Pattern (fallback) + */ +function generateDefaultSlide(slide, slideId, brand) { + // Use title slide pattern as default + return generateTitleSlide(slide, slideId, brand); +} + +/** + * Helper: Convert hex color to RGB object + */ +function hexToRgb(hex) { + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + red: parseInt(result[1], 16) / 255, + green: parseInt(result[2], 16) / 255, + blue: parseInt(result[3], 16) / 255 + } : { red: 0, green: 0, blue: 0 }; +} + +// CLI Interface +function main() { + const args = {}; + + for (let i = 2; i < process.argv.length; i++) { + if (process.argv[i].startsWith('--')) { + const key = process.argv[i].replace(/^--/, ''); + const value = process.argv[i + 1]; + args[key] = value; + i++; + } + } + + if (!args.presentation) { + console.error('Usage: bun slides-adapter.js --presentation presentation.json --account psd [--output slides-spec.json]'); + process.exit(1); + } + + const fs = require('fs'); + const presentation = JSON.parse(fs.readFileSync(args.presentation, 'utf-8')); + + const options = { + account: args.account || 'psd', + brand: args.brand !== 'false' + }; + + const slidesSpec = generateSlidesRequests(presentation, options); + + if (args.output) { + fs.writeFileSync(args.output, JSON.stringify(slidesSpec, null, 2)); + console.log(`Google Slides specification written to ${args.output}`); + } else { + console.log(JSON.stringify(slidesSpec, null, 2)); + } +} + +if (import.meta.main) { + main(); +} + +export { generateSlidesRequests, generateSlideContent, hexToRgb }; diff --git a/skills/presentation-master/package.json b/skills/presentation-master/package.json new file mode 100644 index 0000000..58980ac --- /dev/null +++ b/skills/presentation-master/package.json @@ -0,0 +1,46 @@ +{ + "name": "presentation-master", + "version": "1.2.0", + "description": "World-class presentation creation skill embodying principles from Garr Reynolds, Nancy Duarte, Guy Kawasaki, Seth Godin, TED, Edward Tufte, and Steve Jobs", + "main": "index.js", + "scripts": { + "test": "echo \"No tests yet\" && exit 0", + "validate": "bun scripts/validate-presentation.js", + "analyze": "bun scripts/analyze-context.js", + "suggest-images": "bun scripts/suggest-images.js", + "adapt-pptx": "bun adapters/pptx-adapter.js", + "adapt-slides": "bun adapters/slides-adapter.js" + }, + "keywords": [ + "presentations", + "slides", + "powerpoint", + "google-slides", + "keynote", + "design", + "storytelling", + "presentation-zen", + "nancy-duarte", + "ted-talks", + "visual-communication", + "data-visualization", + "slide-design" + ], + "author": "Geoffrey (Kris Hagel)", + "license": "MIT", + "dependencies": {}, + "devDependencies": {}, + "engines": { + "node": ">=18.0.0", + "bun": ">=1.0.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/hagelk/geoffrey.git", + "directory": "skills/presentation-master" + }, + "bugs": { + "url": "https://github.com/hagelk/geoffrey/issues" + }, + "homepage": "https://github.com/hagelk/geoffrey/tree/main/skills/presentation-master#readme" +} diff --git a/skills/presentation-master/principles/masters.md b/skills/presentation-master/principles/masters.md new file mode 100644 index 0000000..955a02f --- /dev/null +++ b/skills/presentation-master/principles/masters.md @@ -0,0 +1,468 @@ +# Presentation Masters - Best Practices + +Codified wisdom from the world's best presenters and presentation designers. + +## Core Universal Principles + +### 1. Simplicity Above All + +**Garr Reynolds (Presentation Zen)** +> "Restraint in preparation, simplicity in design, naturalness in delivery" + +**Seth Godin** +- Maximum 6 words per slide +- No bullet points +- No transitions/animations + +**TED Guidelines** +- Eliminate headlines and bullet points +- Image-rich, minimal text +- Rather than one complex slide, show several slides with each containing one idea + +**Steve Jobs** +- Sometimes just 19 total words in entire presentations +- Single image or thought per slide + +**Universal Rule**: Less is always more. Every element must earn its place. + +--- + +### 2. Visual Over Textual + +**Garr Reynolds** +> "Narration with pictures is better than narration alone" + +**Richard Mayer (Multimedia Principle)** +> "People learn better from words and pictures than from words alone" + +**Universal Rule**: Show, don't write. Slides support speech, they don't replace it. + +**Application**: +- Use full-bleed images +- Minimal text overlays +- Let visuals carry 80% of the message + +--- + +### 3. Audience as Hero + +**Nancy Duarte** +> "The audience is the hero, the speaker is the mentor" + +**Application**: +- Focus on transformation, not information +- What will the audience be able to do after? +- Their journey, not your expertise + +**Universal Rule**: The presentation is about the audience's journey, not your content. + +--- + +### 4. Story Structure Matters + +**Nancy Duarte's Sparkline** +- Alternate "what is" (current reality) with "what could be" (aspiration) +- Build tension through contrast +- End with transformation + +**Steve Jobs' Rule of Three** +- Every presentation in three parts +- Three key features per product +- More dramatic than two, easier to remember than six + +**TED Structure** +- Hook (first 30 seconds) +- Personal connection +- Core idea with evidence +- Call to action +- Strong close (never end with Q&A) + +**Universal Rule**: Structure creates meaning. Random facts don't stick; stories do. + +--- + +### 5. One Idea Per Slide + +**TED** +> "Rather than one complex slide, show several slides with each containing one idea" + +**Guy Kawasaki** +- 10 slides maximum for hour presentation +- One concept per slide + +**Seth Godin** +- 6 words maximum = one focused thought + +**Universal Rule**: Cognitive load is real. One slide, one concept, one moment. + +--- + +### 6. Rehearsal Is Non-Negotiable + +**Steve Jobs** +- Rehearsed weeks in advance +- Every gesture choreographed +- Nothing left to chance + +**TED** +> "Rehearse, rehearse, rehearse" + +**Universal Rule**: Natural delivery requires unnatural preparation. + +--- + +## Design Principles + +### Typography + +**Font Size Minimums**: +- **TED**: 42 points minimum +- **Guy Kawasaki**: 30 points minimum (the "30" in 10/20/30 rule) +- **Our Standard**: 30pt minimum, 36pt+ preferred + +**Font Choice**: +- **TED**: Sans serif (Helvetica, Verdana) over serif for readability +- **2025 Trends**: Bold serifs and character-filled sans-serifs as design elements +- Limit to 1-2 font families maximum + +**Text Limits**: +- **Seth Godin**: 6 words maximum per slide +- **TED**: 1-2 lines ideal, 6 lines absolute maximum +- No paragraphs, ever + +--- + +### Color & Contrast + +**High Contrast Essential**: +- Minimum 4.5:1 ratio (WCAG AA standard) +- Aim for 7:1+ ratio (WCAG AAA standard) +- Test in bright room conditions + +**Steve Jobs Approach**: +- Large white fonts on dark gradient backgrounds +- Simple, bold color palette + +**Consistency**: +- Use same color palette throughout +- Colors should reinforce brand and message + +--- + +### Layout & Spacing + +**Visual Hierarchy** (Garr Reynolds): +- Make most important information the focal point +- Use size, color, position to guide eye + +**Reading Patterns**: +- Z-pattern for Western audiences (top-left → top-right → bottom-left → bottom-right) +- F-pattern for text-heavy slides (avoid these!) + +**Whitespace** (Essential): +- Creates hierarchy by isolating key points +- Essential for emphasis +- Don't fear empty space + +**CRAP Principles**: +- **C**ontrast: Make different elements very different +- **R**epetition: Repeat design elements for unity +- **A**lignment: Every element should align with something +- **P**roximity: Related items should be grouped + +--- + +### Images + +**Quality Requirements**: +- High-resolution only (TED requirement) +- Must own or have permission +- Avoid generic stock photos +- Images must enhance message, not decorate + +**Types of Images**: +- Data visualizations (charts, graphs) +- Conceptual illustrations +- Real-world photography +- Diagrams and infographics + +--- + +## Guy Kawasaki's 10/20/30 Rule + +**Originally for VC Pitches, Applicable to All Presentations**: + +**10 Slides Maximum** +- Audiences can't comprehend more than 10 concepts in one sitting +- Forces you to identify truly important points + +**20 Minutes Maximum** +- Shorter is better +- Leaves time for discussion +- Respects audience attention span + +**30-Point Font Minimum** +- If you need smaller fonts, you have too much content +- Forces simplicity +- Ensures readability from back of room + +--- + +## Edward Tufte's Data Visualization Principles + +### Graphical Integrity + +**Lie Factor**: Visual representation must tell the truth +- Formula: (Size of effect shown in graphic) / (Size of effect in data) +- Acceptable range: 0.95 to 1.05 +- Outside this range = distortion + +**Rules**: +- Don't use area to show one-dimensional data +- Use consistent scales +- Representations of numbers should be proportional to numerical quantities + +--- + +### Maximize Data-Ink Ratio + +**Data-Ink Ratio** = Data-ink / Total ink used in graphic + +**Eliminate**: +- Chartjunk (unnecessary decoration) +- 3D effects +- Unnecessary grid lines +- Excessive borders +- Non-data backgrounds + +**Maximize**: +- Data points +- Trend lines +- Comparisons +- Actual information + +--- + +### Small Multiples + +Instead of one complex chart, use series of small charts with same axes to show: +- Changes over time +- Comparisons across categories +- Pattern recognition + +--- + +## Mayer's 12 Principles of Multimedia Learning + +### Reducing Extraneous Processing + +1. **Coherence**: Remove extraneous material +2. **Signaling**: Highlight organization and essential material +3. **Redundancy**: Don't show text + say same text verbatim +4. **Spatial Contiguity**: Put related elements near each other +5. **Temporal Contiguity**: Present related elements simultaneously + +### Managing Essential Processing + +6. **Segmentation**: Break into logical chunks +7. **Pretraining**: Introduce key concepts early +8. **Modality**: Graphics + narration better than graphics + on-screen text + +### Fostering Generative Processing + +9. **Multimedia**: Use words + pictures together +10. **Personalization**: Use conversational style +11. **Voice**: Informal voice over formal +12. **Image**: Speaker image not required (focus on content) + +--- + +## Steve Jobs Presentation Techniques + +### Create Moments + +**The Surprise**: +- MacBook Air pulled from envelope +- "One more thing..." +- Rehearsed spontaneity + +**The Demo**: +- Live product demonstrations +- Make it real and tangible +- Show, don't just tell + +**The Analogy**: +- "1,000 songs in your pocket" (not "5GB MP3 player") +- Make it relatable +- Connect to audience experience + +--- + +### The Rule of Three + +**Three Acts**: +- Setup → Conflict → Resolution +- Past → Present → Future +- Problem → Journey → Solution + +**Three Features**: +- Never showed more than 3 key features +- Each feature given dedicated focus +- Memorable and digestible + +--- + +## Common Mistakes to Avoid + +### Critical Errors + +1. **Reading from slides** - Slides support, don't replace you +2. **Too much text** - Paragraphs and long bullets +3. **Poor contrast** - Can't read from back of room +4. **Information overload** - Trying to fit too much +5. **Default templates** - Generic and forgettable +6. **Ending with Q&A** - Always end strong with your message + +--- + +### Design Flaws + +1. **Chart junk** - 3D effects, unnecessary decoration +2. **Inconsistent styling** - Random fonts, colors +3. **Low-res images** - Pixelated, stretched photos +4. **Excessive transitions** - Distracting animations +5. **Bullet point addiction** - Lazy content organization + +--- + +### Content Issues + +1. **Not tailoring to audience** - One size fits all approach +2. **No emotional connection** - Just facts and figures +3. **Missing story arc** - Disjointed information +4. **Too many concepts** - Violating 10-concept rule +5. **Insufficient rehearsal** - "Winging it" + +--- + +## Presentation Type Guidelines + +### Board/Executive Update + +**Characteristics**: +- Data-driven +- Professional tone +- Clear recommendations +- Time-efficient + +**Best Practices**: +- 8-10 slides maximum +- Heavy use of data visualizations +- Clear "What/So What/Now What" structure +- Executive summary up front + +--- + +### Keynote/TED-Style + +**Characteristics**: +- Story-driven +- Emotional connection +- Inspirational +- Transformative + +**Best Practices**: +- 12-15 slides +- Minimal text (<3 words often) +- Personal stories +- Strong emotional arc +- Surprise moments + +--- + +### Training/Educational + +**Characteristics**: +- Process-focused +- Step-by-step +- Retention-optimized +- Practice-oriented + +**Best Practices**: +- 15-20 slides +- Clear progression +- Mayer's principles critical +- Examples and exercises +- Summaries and reviews + +--- + +### Pitch/Sales + +**Characteristics**: +- Problem-solution focused +- Evidence-based +- ROI-driven +- Competitive positioning + +**Best Practices**: +- 10 slides (Kawasaki rule) +- Clear problem statement +- Unique value proposition +- Market validation +- Call to action + +--- + +## Quality Assessment Questions + +Before presenting, ask: + +**Content**: +- Can I explain the core message in one sentence? +- Is there exactly one idea per slide? +- Does each slide support the overall story? +- Is the audience positioned as the hero? + +**Design**: +- Can I read all text from 10 feet away? +- Have I eliminated all non-essential elements? +- Is the visual hierarchy clear? +- Are related elements grouped together? + +**Data** (if applicable): +- Is my lie factor between 0.95-1.05? +- Have I maximized data-ink ratio? +- Are all charts clearly labeled? +- Can I explain the "so what" for each visualization? + +**Story**: +- Does my presentation have clear beginning/middle/end? +- Is there tension and resolution? +- Will the audience remember the key message? +- Have I included a surprise or memorable moment? + +--- + +## Sources & Further Reading + +**Books**: +- Presentation Zen by Garr Reynolds +- Resonate by Nancy Duarte +- slide:ology by Nancy Duarte +- The Visual Display of Quantitative Information by Edward Tufte +- Multimedia Learning by Richard Mayer + +**Articles**: +- Guy Kawasaki: The 10/20/30 Rule of PowerPoint +- Seth Godin: Really Bad PowerPoint +- TED: How to Create Slides for Your TED Talk + +**Websites**: +- presentationzen.com +- duarte.com +- ted.com/participate/organize-a-local-tedx-event/tedx-organizer-guide/speakers-program/prepare-your-speaker + +--- + +**Remember**: These principles are not rigid rules—they're wisdom distilled from thousands of successful presentations. Adapt them to your context, but respect the underlying truths they represent. diff --git a/skills/presentation-master/principles/slide-patterns.md b/skills/presentation-master/principles/slide-patterns.md new file mode 100644 index 0000000..dbefb08 --- /dev/null +++ b/skills/presentation-master/principles/slide-patterns.md @@ -0,0 +1,1057 @@ +# Slide Pattern Library - Comprehensive Guide + +This document provides detailed specifications for six proven slide patterns that form the foundation of world-class presentations. Each pattern has been validated across thousands of successful presentations by masters like Garr Reynolds, Nancy Duarte, and Steve Jobs. + +--- + +## Pattern 1: Title Slide + +### Purpose +Set the tone for the entire presentation and create immediate visual impact. The title slide is the audience's first impression and should establish both the topic and the emotional tenor of what's to come. + +### Core Elements + +**Text Requirements**: +- Title: 3-6 words maximum (Godin principle) +- Subtitle (optional): 5-10 words providing context +- Attribution: Speaker name, date, or organization (minimal, small font) +- Font size: Title 48-72pt, Subtitle 24-36pt, Attribution 14-18pt + +**Visual Treatment**: +- **Option A - Image-Based**: Full-bleed high-quality photograph or illustration that emotionally connects to the topic +- **Option B - Typography-Based**: Bold, clean typography on solid background color (brand color preferred) +- **Option C - Minimalist**: Simple text on white/black background with subtle accent element + +**Layout Specifications**: +- Title positioned in vertical center or upper third (golden ratio positioning) +- Ample whitespace around all elements (minimum 10% margins) +- If using image, ensure text has sufficient contrast (overlay, shadow, or positioning) + +### Design Principles + +**Contrast**: +- Text must have minimum 7:1 contrast ratio against background +- Use overlay gradient (70% opacity recommended) if text on image +- Dark text on light background OR light text on dark background - never midtones + +**Alignment**: +- Center alignment for maximum impact and formality +- Left alignment for more conversational, approachable tone +- Never right-align title slides + +**Color Psychology**: +- Board presentations: Navy, charcoal, or brand primary (professional, trustworthy) +- Keynotes: Bold accent colors (energetic, memorable) +- Training: Lighter, accessible colors (approachable, educational) +- Pitches: Confident colors aligned with brand (credible, distinctive) + +### Examples by Presentation Type + +**Board/Executive Update**: +``` +Title: "Cybersecurity Update" +Subtitle: "Q4 2025 Board Meeting" +Background: Navy (#25424C) with subtle geometric pattern +Font: Sans-serif, bold, 64pt title / 28pt subtitle +Alignment: Center +``` + +**Keynote/TED-Style**: +``` +Title: "The Future of Learning" +Subtitle: (none - let title stand alone) +Background: Full-bleed image of engaged students +Overlay: 60% black gradient from bottom +Font: Modern sans-serif, white, 72pt +Alignment: Lower third positioning +``` + +**Training/Educational**: +``` +Title: "Excel Fundamentals" +Subtitle: "Session 1: Getting Started" +Background: Light gray (#F5F5F5) +Accent: Brand color bar on left (10% width) +Font: Friendly sans-serif, dark gray, 56pt / 24pt +Alignment: Left with padding +``` + +**Pitch/Sales**: +``` +Title: "Revolutionizing EdTech" +Subtitle: "Series A Pitch - November 2025" +Background: Brand primary color with product screenshot (20% opacity) +Font: Brand font, white, 60pt / 22pt +Alignment: Center +``` + +### Common Mistakes to Avoid + +1. **Too much text**: More than 10 words total dilutes impact +2. **Cluttered layout**: Logo, tagline, disclaimer, date all competing +3. **Poor image quality**: Low-resolution or generic stock photos +4. **Weak contrast**: Text hard to read against busy background +5. **Mixed messages**: Image doesn't relate to topic +6. **Default templates**: PowerPoint/Keynote standard templates scream amateur + +### Variations + +**Simple Title Only**: +- Just the presentation title, nothing else +- Maximum impact, extreme minimalism +- Best for confident presenters with strong topic + +**Title + Provocative Question**: +- Title as question that creates curiosity +- Example: "What if AI could learn like humans?" +- Engages audience immediately + +**Title + Powerful Statistic**: +- Title with supporting shocking fact +- Example: "The Education Crisis" + "73% of students unprepared" +- Creates urgency + +--- + +## Pattern 2: One Big Idea + +### Purpose +Communicate a single concept with maximum impact. This pattern is the embodiment of Seth Godin's "6 words or less" principle and creates the most memorable moments in presentations. + +### Core Elements + +**Text Requirements**: +- Absolute maximum: 6 words +- Ideal: 1-3 words +- Font size: 60-120pt (yes, that large) +- Font weight: Bold or heavy preferred +- No punctuation unless essential (question mark, exclamation acceptable) + +**Visual Treatment**: +- **Option A - Text Only**: Massive typography fills the slide +- **Option B - Text + Single Icon**: One simple, clear icon supporting the word +- **Option C - Text + Full-Bleed Image**: Bold text over compelling photograph +- **Option D - Isolated Number**: Giant statistic with minimal context + +**Layout Specifications**: +- Text occupies 40-60% of slide area +- Positioned using rule of thirds or dead center +- Whitespace is essential - minimum 30% empty space +- If using image, ensure it doesn't compete with text + +### Design Principles + +**Emphasis Through Size**: +- Text should be readable from 50+ feet away +- Use optical sizing - adjust for visual balance not mathematical precision +- Heavy font weights prevent text from looking weak at large sizes + +**Color Strategy**: +- Monochromatic: Single color on contrasting background (safest, cleanest) +- Accent color: Key word in accent color, rest neutral (draws eye strategically) +- Brand palette: Use brand colors for consistency + +**Typography Selection**: +- Sans-serif for modern, clean impact (Helvetica, Avenir, Gotham) +- Bold serif for traditional, authoritative feel (Playfair, Garamond Bold) +- Display fonts acceptable if highly readable (avoid decorative) + +### Use Cases + +**Key Statistics**: +``` +"83%" +(That's it. Let the number sink in. Explain verbally.) +``` + +**Transitions**: +``` +"But..." +(Signals shift in narrative) +``` + +**Memorable Phrases**: +``` +"10x Growth" +(Bold claim that demands attention) +``` + +**Questions**: +``` +"Why?" +(Provokes thought, creates curiosity) +``` + +**Moments of Impact**: +``` +"Everything Changed" +(Emotional turning point) +``` + +### Examples by Context + +**Board Update - Key Metric**: +``` +Text: "$2.4M" +Subtitle (small, 18pt): "Cost savings achieved Q4" +Background: White +Text color: Brand primary +Font: Bold sans-serif, 100pt +Position: Center +``` + +**Keynote - Provocative Statement**: +``` +Text: "Obsolete" +Background: Dark red (#8B0000) +Text color: White +Font: Heavy sans-serif, 120pt +Position: Center +Effect: One word conveys urgency of change +``` + +**Training - Concept Introduction**: +``` +Text: "Pivot Tables" +Icon: Simple table/grid icon above text +Background: Light background +Text color: Dark gray +Font: Bold sans-serif, 80pt +Position: Center with icon +``` + +**Pitch - Vision Statement**: +``` +Text: "Accessible" +Background: Full-bleed image of diverse students +Overlay: 40% black from edges +Text color: White +Font: Bold serif, 90pt +Position: Lower third +``` + +### Common Mistakes to Avoid + +1. **Too many words**: Seven+ words destroys the impact +2. **Too small**: Font under 60pt defeats the purpose +3. **Complexity**: Adding unnecessary elements dilutes focus +4. **Weak fonts**: Thin or light weights disappear at distance +5. **Poor word choice**: Generic words lack punch ("Important" vs "Critical") +6. **Overuse**: Every slide can't be "one big idea" - save for key moments + +### Advanced Techniques + +**Progressive Revelation**: +- Start with one word +- Next slide adds second word +- Builds phrase progressively +- Creates narrative momentum + +**Numerical Sequences**: +``` +Slide 1: "3" +Slide 2: "Breakthroughs" +Slide 3: "That Changed Everything" +``` + +**Contrasting Pairs**: +``` +Slide 1: "Then" (old way) +Slide 2: "Now" (new way) +Creates before/after impact +``` + +--- + +## Pattern 3: Visual + Caption + +### Purpose +Combine the power of imagery with minimal explanatory text. This is the workhorse pattern for visual storytelling - the image carries 80% of the message, the caption provides critical context. + +### Core Elements + +**Visual Requirements**: +- High-resolution image: Minimum 1920x1080 for 16:9, ideally 2K or 4K +- Image quality: Professional photography or high-quality illustration +- Relevance: Image must directly relate to and reinforce the message +- Composition: Clear focal point, uncluttered background +- Aspect ratio: Should fill 70-90% of slide area + +**Caption Specifications**: +- Text length: 5-15 words maximum (one line ideal) +- Font size: 24-36pt +- Position: Usually bottom third, sometimes top or side +- Background treatment: Solid bar, gradient, or none if contrast sufficient +- Alignment: Usually left-aligned, centered for impact + +**Layout Options**: + +**Option A - Full Bleed with Bottom Caption**: +``` +Image: Fills entire slide +Caption: Bottom 15% of slide +Caption background: Semi-transparent bar (70-80% opacity) +Text: White or light color +Padding: 20pt all sides of caption +``` + +**Option B - Image with Side Caption**: +``` +Image: Left 70% of slide +Caption area: Right 30% +Caption background: Solid brand color +Text: Contrasting color +Vertical alignment: Center +``` + +**Option C - Image with Floating Caption**: +``` +Image: Full slide +Caption: Positioned over negative space in image +Background: Subtle shadow or outline for legibility +Text: Color depends on background +``` + +### Design Principles + +**Image Selection Criteria**: +1. **Authenticity**: Prefer real photos over generic stock imagery +2. **Emotion**: Image should evoke appropriate emotional response +3. **Simplicity**: Clear subject, uncluttered composition +4. **Quality**: Crisp, well-lit, professionally captured +5. **Relevance**: Obvious connection to message (avoid metaphors audience must decode) + +**Caption Writing**: +- **Descriptive**: "Students engaged in hands-on learning" +- **Interpretive**: "This is what transformation looks like" +- **Statistical**: "73% improvement in engagement scores" +- **Narrative**: "Where it all began - June 2020" +- **Provocative**: "Everything you know is wrong" + +**Color Coordination**: +- Extract dominant colors from image for caption background +- Ensure caption doesn't clash with image colors +- Use complementary colors for accent and harmony + +### Use Cases by Presentation Type + +**Board Update - Evidence**: +``` +Image: Bar chart showing growth trend +Caption: "Revenue up 34% year-over-year" +Layout: Full-bleed chart +Caption: Bottom bar, white text on dark background +Purpose: Concrete evidence of success +``` + +**Keynote - Emotional Moment**: +``` +Image: Powerful photograph of impact (students, customers, etc.) +Caption: "This is why we do what we do" +Layout: Full-bleed image +Caption: Lower third, white text with subtle shadow +Purpose: Create emotional connection +``` + +**Training - Example**: +``` +Image: Screenshot or diagram showing concept +Caption: "Notice how the formula references cell A1" +Layout: Image fills slide +Caption: Top banner, dark text on light background +Purpose: Clear visual instruction +``` + +**Pitch - Problem Illustration**: +``` +Image: Photograph showing problem state +Caption: "Current classroom reality" +Layout: Full-bleed image +Caption: Bottom, white text on semi-transparent overlay +Purpose: Establish problem before solution +``` + +### Examples + +**Example 1: Impact Story** +``` +Visual: Close-up photo of student working intently on project +Caption: "Engagement increased 89% with new curriculum" +Layout: Full-bleed image +Caption Position: Bottom third +Caption Background: Black bar, 75% opacity +Text: White, 28pt, left-aligned with 30pt left padding +Effect: Human face + concrete data = compelling evidence +``` + +**Example 2: Before/After** +``` +Slide 1: +Visual: Dated classroom with rows of desks +Caption: "Traditional learning environment" +Layout: Full-bleed +Caption: Simple bottom text, white with drop shadow + +Slide 2: +Visual: Modern collaborative learning space +Caption: "Reimagined for 2025" +Layout: Same as Slide 1 +Effect: Visual contrast reinforces transformation narrative +``` + +**Example 3: Process Step** +``` +Visual: Diagram or photo showing specific step +Caption: "Step 3: Connect the data sources" +Layout: Image 80% of slide +Caption: Right sidebar, brand color background +Text: White, 24pt +Icon: Small numbered circle "3" above text +Effect: Clear, sequential instruction +``` + +### Common Mistakes to Avoid + +1. **Generic stock photos**: Fake-looking people with forced smiles +2. **Caption too long**: Paragraph of text defeats the visual-first purpose +3. **Poor image quality**: Pixelated, stretched, or low-resolution images +4. **Competing elements**: Image and caption fight for attention +5. **Illegible text**: Caption lacks sufficient contrast with background +6. **Irrelevant imagery**: Image is decorative, not meaningful +7. **Busy backgrounds**: Too much visual noise distracts from message + +### Advanced Techniques + +**Ken Burns Effect** (if presenting digitally): +- Slow zoom on static image +- Creates motion and maintains interest +- Use sparingly - can be distracting if overused + +**Split Image**: +``` +Left 50%: Before image +Right 50%: After image +Caption: Center, spanning both - "6-month transformation" +Effect: Direct visual comparison +``` + +**Image Series**: +``` +Three images on one slide (each 33% width) +Single caption below: "Three approaches to the same problem" +Effect: Comparison without clutter +``` + +**Annotated Images**: +``` +Image: Screenshot or diagram +Annotations: Minimal callouts (arrows, circles, labels) +Caption: "Focus on the highlighted section" +Effect: Guides attention to specific elements +``` + +--- + +## Pattern 4: Data Visualization + +### Purpose +Present quantitative information in the clearest, most truthful, and most impactful way possible. This pattern follows Edward Tufte's principles of graphical integrity and maximum data-ink ratio. + +### Core Principles (Tufte) + +**Graphical Integrity**: +1. **Lie Factor** = (Size of effect shown in graphic) / (Size of effect in data) + - Acceptable range: 0.95 to 1.05 + - Outside this range = distortion +2. **Representation of numbers should be proportional to numerical quantities** +3. **Use clear, detailed labeling** - avoid ambiguity +4. **Show data variation, not design variation** + +**Maximize Data-Ink Ratio**: +- **Data-ink**: Ink used to display actual data +- **Non-data-ink**: Everything else (borders, backgrounds, decorations) +- **Goal**: Maximize (data-ink / total ink) +- **Method**: Remove everything that isn't data + +### Chart Type Selection + +**Line Charts**: +- **Best for**: Trends over time, continuous data +- **When to use**: Showing change, trajectory, patterns +- **Data requirements**: At least 5-7 data points for meaningful trend +- **Key features**: Clear axis labels, legend if multiple lines, gridlines minimal + +**Bar Charts**: +- **Best for**: Comparing discrete categories +- **When to use**: Comparing quantities across categories +- **Orientation**: Vertical (column) for time-based, horizontal for categorical +- **Key features**: Bars should touch or have minimal spacing, start axis at zero + +**Scatter Plots**: +- **Best for**: Showing relationships between two variables +- **When to use**: Correlation analysis, clustering, outlier detection +- **Key features**: Clear axis scaling, trend line if appropriate, labeled outliers + +**Pie Charts** (use rarely): +- **Best for**: Parts of a whole (ONLY if <5 segments) +- **When to use**: Showing simple proportions (avoid if possible) +- **Better alternative**: Bar chart is almost always clearer +- **If must use**: Start at 12 o'clock, go clockwise, label directly + +**Small Multiples**: +- **Best for**: Comparing patterns across multiple categories +- **When to use**: Same data structure repeated across segments +- **Key features**: Identical scales, same chart type, grid layout +- **Example**: Sales trends for each region, same date range + +### Design Specifications + +**Typography for Data**: +- Axis labels: 14-18pt, sans-serif +- Data labels: 12-16pt, shown sparingly (only key values) +- Title: 24-28pt, descriptive not generic +- Source citation: 10-12pt, bottom right corner + +**Color for Data**: +- **Single series**: One color, varying shade for emphasis +- **Multiple series**: Distinct colors (colorblind-safe palette) +- **Diverging data**: Blue-white-red or similar +- **Categorical**: Distinct hues with sufficient contrast +- **Avoid**: Traffic light colors (red/yellow/green) unless truly stop/caution/go + +**Elements to Eliminate** (Chart Junk): +1. 3D effects - distort perception of quantities +2. Unnecessary gridlines - use sparingly, light gray +3. Bold borders around chart area - use minimal or none +4. Decorative backgrounds - solid white or very light gray only +5. Default color gradients - use flat colors +6. Excessive tick marks - show only necessary intervals +7. Redundant labels - if in legend, don't label each bar + +**Elements to Emphasize**: +1. Data points/bars/lines - these are the story +2. Key values - highlight the insight +3. Trend lines - if they reveal pattern +4. Annotations - explain anomalies or key points +5. Scale - always clear what units represent + +### Example Specifications + +**Example 1: Revenue Growth (Line Chart)** +``` +Chart Type: Line chart +Data: Quarterly revenue, 2023-2025 +Layout: Chart fills 80% of slide +Title: "34% Revenue Growth Over 3 Years" +X-Axis: Quarters (Q1 2023 → Q4 2025) +Y-Axis: Revenue ($M), starting at 0 +Line: Bold (3pt), brand primary color +Gridlines: Horizontal only, light gray (10% opacity), major intervals +Annotation: Arrow pointing to Q3 2025 → "New product launch" +Data labels: Start, end, and peak values only +Background: White +Font: Sans-serif throughout +``` + +**Example 2: Category Comparison (Bar Chart)** +``` +Chart Type: Horizontal bar chart +Data: Student performance by subject (5 subjects) +Layout: Chart fills 75% of slide, centered +Title: "Math Scores Lead Academic Performance" +X-Axis: Percentage (0-100%) +Y-Axis: Subject names +Bars: All same color except highest (Math) - highlighted in brand accent +Spacing: Minimal between bars +Data labels: End of each bar showing exact percentage +Gridlines: Vertical, light gray, every 20% +Background: Light gray (#F5F5F5) +``` + +**Example 3: Comparison Across Segments (Small Multiples)** +``` +Chart Type: 4 identical line charts in 2x2 grid +Data: Usage patterns for 4 customer segments +Layout: Each chart 45% of slide width/height +Titles: Customer segment name above each +Shared Y-axis: Usage frequency (0-100) +Shared X-axis: Months (Jan-Dec) +Lines: Same brand color in all four +Gridlines: Minimal, shared scales +Annotation: Overall title "Usage Patterns Vary By Segment" +Background: White with subtle dividing lines between charts +``` + +### Common Mistakes to Avoid + +1. **Non-zero baseline**: Bar charts not starting at zero distort perception +2. **Dual-axis abuse**: Two Y-axes can manipulate correlation appearance +3. **Too many data series**: More than 4-5 lines becomes spaghetti chart +4. **Missing context**: No title, source, or units +5. **Misleading scales**: Logarithmic when linear expected, or truncated range +6. **Decorative over functional**: Prioritizing aesthetics over clarity +7. **3D pie charts**: The worst offender - distorts all proportions +8. **Tiny fonts**: Data labels too small to read +9. **Rainbow colors**: Using every color destroys visual hierarchy +10. **Chart junk**: Unnecessary backgrounds, borders, shadows, gradients + +### Advanced Techniques + +**Sparklines** (Tufte): +- Tiny line charts embedded in text or tables +- Show trend without axes or labels +- Effective for showing many trends simultaneously +- Example: "Revenue $2.4M [tiny trend line showing up/down]" + +**Slopegraphs**: +- Compare two points in time +- Lines connect same category across time periods +- Slope shows change (up/down/flat) +- Cleaner than bar chart for before/after + +**Dot Plots**: +- Alternative to bar charts +- Shows value as positioned dot +- Reduces ink, increases clarity +- Especially good for many categories + +**Annotated Charts**: +- Add explanatory text directly on chart +- Arrow pointing to significant data point +- "Here's where policy changed" +- Makes insight explicit, not just implied + +--- + +## Pattern 5: Timeline / Process + +### Purpose +Show progression, sequence, or chronological flow. This pattern makes complex processes understandable and temporal relationships clear. + +### Core Elements + +**Structure Requirements**: +- 3-7 steps maximum (cognitive load limit) +- Each step labeled clearly +- Visual connection between steps (arrows, lines, numbers) +- Minimal text per step (5-10 words) +- Consistent visual treatment across all steps + +**Visual Treatment Options**: + +**Option A - Horizontal Linear**: +``` +[Step 1] → [Step 2] → [Step 3] → [Step 4] +Left to right progression (Western reading) +Equal spacing between elements +Arrow or line connecting +``` + +**Option B - Vertical Linear**: +``` +[Step 1] + ↓ +[Step 2] + ↓ +[Step 3] +``` +Top to bottom (natural gravity/sequence) +Good for processes with sub-steps +``` + +**Option C - Circular/Cyclical**: +``` + [Step 1] + ↙ ↖ + [Step 4] [Step 2] + ↖ ↙ + [Step 3] +``` +For processes that repeat +Shows no definitive end +``` + +**Option D - Timeline with Dates**: +``` +2020 ----•---- 2022 ----•---- 2024 ----•---- 2026 + Event Event Event Future +Historical progression +Specific dates marked +``` + +### Design Specifications + +**Step Containers**: +- Shape: Rectangles, circles, or rounded rectangles (consistent) +- Size: Large enough for text (minimum 150pt x 150pt) +- Color: Sequential (lightest to darkest) OR consistent with one highlighted +- Border: Optional, 2-4pt if used +- Spacing: 40-60pt between containers + +**Connectors**: +- Arrows: Bold (4-6pt), simple style +- Lines: Straight or curved, 3-5pt thickness +- Color: Neutral gray or brand color +- Style: Avoid fancy arrowheads - simple is best + +**Text Treatment**: +- Step number/label: Bold, 18-24pt +- Step description: Regular, 14-18pt +- Alignment: Centered within container +- Line spacing: 1.3-1.5x + +**Icons** (optional): +- Simple, flat design icons +- Positioned above or beside step label +- Size: 40-60pt +- Color: Match step container or accent color + +### Use Cases + +**Project Roadmap**: +``` +Q1 2025: Discovery → Q2 2025: Design → Q3 2025: Build → Q4 2025: Launch +Each quarter as step +Timeline shows progression +Current position highlighted +``` + +**Process Flow**: +``` +1. Intake → 2. Assessment → 3. Planning → 4. Implementation → 5. Review +Clear sequential process +Numbered steps +Arrows show direction +``` + +**Historical Timeline**: +``` +2020: Founded → 2022: Series A → 2024: Expansion → 2026: IPO (projected) +Company milestones +Mix of past and future +Visual distinction between actual and planned +``` + +**Instructional Steps**: +``` +Step 1 Step 2 Step 3 +↓ ↓ ↓ +[Screenshot 1] [Screenshot 2] [Screenshot 3] +"Click File" "Select Export" "Choose PDF" +Visual + textual instruction +``` + +### Examples by Presentation Type + +**Board Update - Quarterly Progress**: +``` +Visual: Horizontal timeline +Steps: 4 quarters +Design: +- Q1-Q3: Filled circles (completed) +- Q4: Outlined circle (current) +- Each with 2-line label: "Q3 2025" / "Product Beta" +- Line connecting all +Color: Completed = brand green, Current = brand primary +Background: White +``` + +**Keynote - Transformation Journey**: +``` +Visual: Ascending diagonal path +Steps: 3 major phases +Design: +- Large numbers (1, 2, 3) in circles +- Short phase name below each +- Arrow path between +- Increasing opacity to show progression +Text: Bold numbers (48pt), labels (24pt) +Background: Gradient light to dark +Effect: Visual metaphor of climbing/growing +``` + +**Training - Process Steps**: +``` +Visual: Vertical flowchart +Steps: 5 sequential actions +Design: +- Rounded rectangles +- Numbered 1-5 +- Down arrows between +- Each step: Icon + label + brief description +- Current step highlighted in different color +Background: Light background +Effect: Clear, easy to follow instruction +``` + +**Pitch - Traction Timeline**: +``` +Visual: Horizontal timeline with milestones +Steps: Key achievements from founding to present +Design: +- Timeline bar at bottom +- Milestones as points above bar +- Date labels below bar +- Achievement labels above +- Exponential growth implied by increasing frequency +Color: Milestones in accent color, bar in neutral +``` + +### Common Mistakes to Avoid + +1. **Too many steps**: More than 7 becomes overwhelming +2. **Inconsistent spacing**: Irregular gaps imply irregular timing (unless intentional) +3. **Unclear sequence**: Ambiguous flow direction +4. **Too much text**: Paragraph descriptions defeat visual flow purpose +5. **Weak connectors**: Arrows too thin or unclear +6. **Visual clutter**: Mixing too many icon styles, shapes, colors +7. **Poor hierarchy**: All steps look equally important when some are not +8. **Missing context**: Timeline without dates, process without start/end labels + +### Advanced Techniques + +**Branching Paths**: +``` + Step 1 + ↓ + ↙ ↓ ↘ +Option A B C + ↘ ↓ ↙ + Outcome +``` +Shows decision points +Multiple paths to result +``` + +**Parallel Processes**: +``` +Process A: Step 1 → Step 2 → Step 3 + ↓ ↓ ↓ +Process B: Step 1 → Step 2 → Step 3 +``` +Two simultaneous workflows +Vertical alignment shows synchronization +``` + +**Swimlane Diagram**: +``` +Customer: Action → Wait → Receive +Company: Receive → Process → Deliver +System: Log → Notify → Archive +``` +Who does what when +Horizontal lanes by actor +``` + +--- + +## Pattern 6: Transition / Section Break + +### Purpose +Signal major shifts in the presentation narrative. These slides are the chapter breaks in your presentation story - they give the audience a mental pause and prepare them for a new direction. + +### Core Elements + +**Text Requirements**: +- Absolute minimum: 1 word +- Maximum: 5 words +- Font size: 60-100pt +- Weight: Bold to Extra Bold +- Purpose: Signal change, not inform + +**Visual Treatment**: +- **Option A - Simple Text**: One word/phrase on solid background +- **Option B - Visual Metaphor**: Image representing the transition +- **Option C - Chapter Number**: "Part 2" or "03" with section name +- **Option D - Question**: Provocative question leading to next section + +**Color Strategy**: +- Different from surrounding slides (signals change) +- Often higher contrast or inverted from main deck +- Brand color acceptable but not required + +### Design Specifications + +**Minimal Approach**: +``` +Text: "But..." +Background: Solid color (inverted from previous slides) +Font: Bold sans-serif, 80pt +Position: Dead center +Effect: Creates pause, signals shift +``` + +**Chapter Style**: +``` +Text: "Part 2" (small, 24pt, top) + "The Solution" (large, 64pt, center) +Background: Full-bleed image or gradient +Design: Number and title stacked +Effect: Clear chapter structure +``` + +**Metaphorical**: +``` +Text: "The Turning Point" +Visual: Image of path diverging, door opening, bridge, etc. +Overlay: Text over image with sufficient contrast +Effect: Visual reinforces narrative shift +``` + +### Use Cases + +**From Problem to Solution**: +``` +Transition: "The Answer" +Color: Shift from dark (problem) to light (solution) +Font: Bold, optimistic +Position: Center +``` + +**Between Main Sections**: +``` +Part 1 slides → Transition: "Part 2" → Part 2 slides +Visual: Different background color for transition +Text: Large number + section name +``` + +**Rhetorical Question**: +``` +Text: "What if we could?" +Background: Thought-provoking image +Effect: Creates anticipation for next section +``` + +**Timeline Break**: +``` +Past slides → Transition: "Today" → Future slides +Visual: Timeline element or calendar icon +Color: Distinct from both past and future +``` + +### Examples by Presentation Type + +**Board Update - Section Break**: +``` +Between: "Results" and "Recommendations" +Text: "Looking Forward" +Background: Brand primary color +Font: Brand font, white, 72pt, center +Duration: Brief pause, no narration needed +Effect: Signals shift from analysis to action +``` + +**Keynote - Emotional Shift**: +``` +After: Series of problem slides +Transition: "But what if..." +Background: Black +Text: White, italic, 64pt, center +Visual: Slight pause in delivery +Effect: Creates dramatic tension before solution reveal +``` + +**Training - Module Break**: +``` +Between: Module 1 and Module 2 +Text: "Module 2" (top, 24pt) + "Data Analysis" (center, 56pt) +Background: Light gray with module icon +Include: Progress indicator (2 of 5) +Effect: Clear structure, shows progress +``` + +**Pitch - Credibility Shift**: +``` +After: Product demo slides +Before: Team/traction slides +Text: "Who We Are" +Background: Team photo (blurred) with overlay +Font: Bold, confident +Effect: Transition from what to who +``` + +### Common Mistakes to Avoid + +1. **Too much information**: Transition slide with paragraph of text +2. **Inconsistent use**: Only some sections have breaks +3. **Weak visual distinction**: Looks too similar to content slides +4. **Too frequent**: Transition after every slide dilutes impact +5. **Unnecessary decoration**: Fancy animations or effects +6. **Missing purpose**: Generic "Next" instead of meaningful signal + +### Advanced Techniques + +**Countdown Structure**: +``` +"3 Reasons This Matters" +→ [Reason 1 slide] +→ "2 More Reasons" +→ [Reason 2 slide] +→ "Final Reason" +→ [Reason 3 slide] +``` +Creates anticipation +Shows progress through list +``` + +**Perspective Shift**: +``` +"From the outside..." +→ [External viewpoint slides] +→ "From the inside..." +→ [Internal perspective slides] +``` + +**Time Travel**: +``` +"Five Years Ago" +→ [Historical slides] +→ "Today" +→ [Current slides] +→ "Five Years From Now" +→ [Future slides] +``` + +--- + +## Pattern Selection Matrix + +| Presentation Type | Pattern 1 (Title) | Pattern 2 (Big Idea) | Pattern 3 (Visual+Caption) | Pattern 4 (Data) | Pattern 5 (Timeline) | Pattern 6 (Transition) | +|-------------------|-------------------|----------------------|----------------------------|------------------|----------------------|------------------------| +| **Board Update** | 10% | 10% | 30% | 40% | 5% | 5% | +| **Keynote** | 10% | 40% | 30% | 5% | 10% | 5% | +| **Training** | 10% | 5% | 20% | 30% | 30% | 5% | +| **Pitch** | 10% | 30% | 25% | 30% | 5% | 0% | + +--- + +## Mixing Patterns Effectively + +**Rule of Variation**: +- Never use same pattern for more than 3 consecutive slides +- Alternate between high-impact (Pattern 2) and supportive (Pattern 3, 4) +- Use transitions (Pattern 6) to reset audience attention + +**Visual Rhythm**: +- Pattern 1 (Title) → Pattern 3 → Pattern 3 → Pattern 6 → Pattern 2 → Pattern 4 → Pattern 3... +- Creates flow: Introduction → Evidence → Evidence → Shift → Impact → Data → Evidence + +**Energy Management**: +- High energy: Patterns 1, 2, 6 +- Medium energy: Pattern 3 +- Lower energy: Patterns 4, 5 (require more processing) +- Alternate to maintain engagement + +--- + +## Accessibility Considerations + +**For All Patterns**: +- Minimum font size: 30pt (preferably 36pt+) +- Contrast ratio: 4.5:1 minimum (7:1 preferred) +- Color: Never rely solely on color to convey meaning +- Alt text: Describe images for screen readers (future enhancement) +- Animations: Avoid or allow pause/control + +--- + +This comprehensive pattern library provides the foundation for creating presentations that are simultaneously beautiful, clear, and impactful. Master these six patterns and their variations, and you'll have the tools to create world-class presentations for any context. diff --git a/skills/presentation-master/principles/story-frameworks.md b/skills/presentation-master/principles/story-frameworks.md new file mode 100644 index 0000000..17a3055 --- /dev/null +++ b/skills/presentation-master/principles/story-frameworks.md @@ -0,0 +1,976 @@ +# Story Frameworks - Comprehensive Guide + +Great presentations aren't collections of slides—they're stories. This document details proven narrative structures from the world's best presenters and storytellers, providing specific frameworks you can apply to any presentation. + +--- + +## Why Story Structure Matters + +### The Science + +**Cognitive Processing**: +- Stories activate more parts of the brain than facts alone +- Narrative structure helps memory consolidation +- Emotional engagement increases retention by 65-70% +- Pattern recognition makes information easier to recall + +**Psychological Impact**: +- Stories create empathy and connection +- Narrative arc sustains attention through tension/resolution +- Relatable characters (even abstract ones) engage audience +- Transformation provides satisfying conclusion + +**Communication Efficiency**: +- Structure eliminates "what comes next?" confusion +- Clear framework helps presenter stay on track +- Audience can follow complex information more easily +- Memorable structure aids post-presentation recall + +### The Problem with "Information Dumps" + +**Why Random Facts Fail**: +- No connective tissue between points +- Audience can't predict where you're going +- Equal weight given to all information +- No emotional journey +- Forgettable within hours + +**What Structure Provides**: +- Predictable (but interesting) flow +- Rising and falling action +- Emphasis through positioning +- Emotional engagement +- Memorable narrative + +--- + +## Framework 1: Nancy Duarte's Sparkline + +### Overview + +Nancy Duarte analyzed hundreds of successful presentations and discovered a pattern: the best presenters alternate between "what is" (current reality) and "what could be" (aspirational future), creating a sparkline that builds tension until resolving in a transformed new reality. + +### The Structure + +``` +What Is (Reality) ────┐ + ↓ + What Could Be (Aspiration) + ↑ +What Is (Obstacle) ───┘ + ↓ + What Could Be (Vision) + ↑ +What Is (Challenge) ──┘ + ↓ + What Could Be (Transformation) + ↑ + ───┘ + New Bliss (Transformed Reality) +``` + +**The Pattern**: +1. Start with current reality (what is) +2. Contrast with what could be +3. Return to reality to show obstacle +4. Present vision of overcoming it +5. Show another challenge +6. Present bigger vision +7. Build to crescendo +8. End with new transformed reality + +### Detailed Breakdown + +**Act 1: What Is (Current Reality)** +- **Purpose**: Establish baseline, create identification +- **Duration**: 10-15% of presentation +- **Content**: Current state, familiar situation, status quo +- **Tone**: Matter-of-fact, relatable +- **Example**: "Today, students spend 6 hours in traditional classrooms..." + +**Act 2: What Could Be (First Aspiration)** +- **Purpose**: Create contrast, spark imagination +- **Duration**: 5-10% of presentation +- **Content**: Brief glimpse of possibility +- **Tone**: Hopeful, intriguing +- **Example**: "Imagine if they could learn at their own pace, exploring what they're curious about..." + +**Act 3: What Is (First Obstacle)** +- **Purpose**: Acknowledge challenges, build credibility +- **Duration**: 10-15% of presentation +- **Content**: Real barriers, legitimate concerns +- **Tone**: Honest, not dismissive +- **Example**: "But our current infrastructure doesn't support personalized learning at scale..." + +**Act 4: What Could Be (Expanded Vision)** +- **Purpose**: Show how obstacle can be overcome +- **Duration**: 10-15% of presentation +- **Content**: Specific solutions, evidence +- **Tone**: Confident, inspiring +- **Example**: "With adaptive learning platforms, each student could have a customized curriculum..." + +**Act 5: What Is (Deeper Challenge)** +- **Purpose**: Raise stakes, show full scope +- **Duration**: 10-15% of presentation +- **Content**: Systemic issues, harder problems +- **Tone**: Serious, urgent +- **Example**: "The real challenge isn't technology—it's transforming teacher mindset and assessment methods..." + +**Act 6: What Could Be (Ultimate Vision)** +- **Purpose**: Present comprehensive transformation +- **Duration**: 15-20% of presentation +- **Content**: Full picture of change, compelling future +- **Tone**: Bold, inspiring +- **Example**: "When we reimagine education entirely, students don't just learn—they discover who they are..." + +**Act 7: New Bliss (Transformed Reality)** +- **Purpose**: Land the vision, call to action +- **Duration**: 10-15% of presentation +- **Content**: What life looks like after transformation +- **Tone**: Aspirational, actionable +- **Example**: "This is the future of learning—and it starts with what we decide today." + +### Application Guidelines + +**Best Used For**: +- Keynote speeches +- Vision presentations +- Change management +- Inspirational talks +- Fundraising pitches +- Long-form presentations (20+ minutes) + +**Not Recommended For**: +- Quick updates (under 10 minutes) +- Pure data presentations +- Training/how-to sessions +- Time-constrained board meetings + +**Slide Count Implications**: +- Minimum: 12-15 slides +- Optimal: 18-25 slides +- Pattern: 2-3 slides per "what is," 2-3 slides per "what could be" + +### Example: Education Technology Pitch + +**Slide 1-2 (What Is)**: Current education system—standardized, one-size-fits-all +**Slide 3-4 (What Could Be)**: Personalized learning paths +**Slide 5-6 (What Is)**: Current technology inadequate, teacher resistance +**Slide 7-9 (What Could Be)**: Our platform + professional development +**Slide 10-11 (What Is)**: Broader systemic challenges +**Slide 12-15 (What Could Be)**: Complete transformation vision +**Slide 16-17 (New Bliss)**: Students thriving, teachers empowered, results proven +**Slide 18 (Call to Action)**: Join us in transforming education + +### Tips for Success + +**Create Real Contrast**: +- Don't make "what is" too bleak or "what could be" too unrealistic +- Contrast should be significant but believable +- Use specific examples, not generalities + +**Build Tension**: +- Each "what is" should raise slightly different challenges +- Don't repeat same obstacle +- Escalate the stakes progressively + +**Earn the Vision**: +- Don't jump to big vision too early +- Build credibility through smaller contrasts first +- Show you understand obstacles before presenting solutions + +**Visual Representation**: +- Use darker colors/images for "what is" slides +- Use lighter/brighter for "what could be" slides +- Visual distinction reinforces narrative contrast + +--- + +## Framework 2: Steve Jobs' Rule of Three + +### Overview + +Steve Jobs structured every presentation around the number three. Three main sections. Three key features. Three supporting points. This wasn't arbitrary—it's rooted in cognitive science and storytelling tradition. + +### Why Three Works + +**Cognitive Load**: +- Two items: Too simple, lacks pattern +- Three items: Perfect pattern recognition +- Four+ items: Difficult to remember +- Three balances complexity with memorability + +**Storytelling Tradition**: +- Three-act structure (setup, confrontation, resolution) +- Three wishes in fairy tales +- Three little pigs, three bears, three musketeers +- Cultural familiarity makes it instantly recognizable + +**Rhetorical Power**: +- "Life, liberty, and the pursuit of happiness" +- "Government of the people, by the people, for the people" +- "Blood, sweat, and tears" +- Tricolon creates rhythm and emphasis + +### The Structure + +**Level 1: Three Main Sections** +``` +ACT 1: Setup (25% of presentation) + └─ Establish context, introduce topic + +ACT 2: Confrontation (50% of presentation) + └─ Explore depth, show features/evidence + +ACT 3: Resolution (25% of presentation) + └─ Conclusion, call to action +``` + +**Level 2: Three Points Per Section** +``` +ACT 1: Setup + ├─ Point 1: Current situation + ├─ Point 2: Problem/opportunity + └─ Point 3: Why now matters + +ACT 2: Confrontation + ├─ Point 1: First key feature/benefit + ├─ Point 2: Second key feature/benefit + └─ Point 3: Third key feature/benefit + +ACT 3: Resolution + ├─ Point 1: What this means + ├─ Point 2: What you should do + └─ Point 3: What the future looks like +``` + +**Level 3: Three Supporting Elements Per Point** +``` +Feature 1 + ├─ What it is + ├─ Why it matters + └─ Proof/example +``` + +### Detailed Breakdown + +**Act 1: Setup (Minutes 1-5 of 20-minute presentation)** + +*Purpose: Hook attention, establish relevance* + +**Point 1: The Hook (1-2 minutes)** +- Surprising statistic, provocative question, or bold statement +- Creates immediate engagement +- Example: "73% of students can't apply what they learn in school" + +**Point 2: The Context (1-2 minutes)** +- Why this topic matters now +- Broader landscape or trend +- Example: "As AI transforms the workplace, education must evolve" + +**Point 3: The Promise (1-2 minutes)** +- What audience will get from this presentation +- Sets expectations +- Example: "Today I'll show you three ways we're solving this" + +**Act 2: Confrontation (Minutes 6-15 of 20-minute presentation)** + +*Purpose: Deliver core value, show evidence* + +**Feature/Point 1 (3-4 minutes)** +- Introduction: What is this feature/point? +- Explanation: How does it work? +- Demo/Example: Show it in action +- Benefit: Why does it matter? + +**Feature/Point 2 (3-4 minutes)** +- Same structure as Feature 1 +- Should build on or complement first point +- Adds new dimension, doesn't repeat + +**Feature/Point 3 (3-4 minutes)** +- Same structure +- Often the most powerful or surprising +- "One more thing..." moment if applicable +- Culmination of the three + +**Act 3: Resolution (Minutes 16-20 of 20-minute presentation)** + +*Purpose: Land the message, inspire action* + +**Summary (1-2 minutes)** +- Quickly recap the three main points +- Reinforce core message +- Example: "We've seen how personalization, engagement, and measurement transform learning" + +**Implication (1-2 minutes)** +- What this means for audience +- Broader significance +- Example: "This isn't just better education—it's preparing students for an unknowable future" + +**Call to Action (1-2 minutes)** +- Specific next steps +- Clear ask +- Inspiring close +- Example: "Join us in reimagining education. Let's talk after about pilot opportunities." + +### Application Guidelines + +**Best Used For**: +- Product launches +- Feature demonstrations +- Persuasive presentations +- Short-to-medium presentations (15-30 minutes) +- When you have natural groupings of concepts + +**Not Recommended For**: +- Complex technical deep-dives requiring more categories +- Highly detailed training +- Presentations where content doesn't naturally group into threes + +**Slide Count Implications**: +- Minimum: 10 slides (following Kawasaki's 10/20/30 rule) +- Typical: 12-18 slides +- Pattern: + - Act 1: 3-4 slides + - Act 2: 6-9 slides (2-3 per feature) + - Act 3: 3-4 slides + +### Example: Product Launch + +**ACT 1: Setup (Slides 1-3)** +- Slide 1 (Title): Product name and tagline +- Slide 2 (Problem): Current pain point—"Students forget 70% within 24 hours" +- Slide 3 (Promise): "Three breakthroughs that change everything" + +**ACT 2: Three Features (Slides 4-12)** +- Slides 4-6 (Feature 1): Adaptive spaced repetition + - Slide 4: What it is + - Slide 5: How it works (demo) + - Slide 6: Results—"85% retention improvement" +- Slides 7-9 (Feature 2): Real-time engagement tracking + - Slide 7: What it is + - Slide 8: Dashboard demo + - Slide 9: Teacher testimonial +- Slides 10-12 (Feature 3): AI-generated practice problems + - Slide 10: What it is + - Slide 11: Examples + - Slide 12: Student success story + +**ACT 3: Resolution (Slides 13-15)** +- Slide 13: Quick recap—"Remember: Adapt, Track, Practice" +- Slide 14: Vision—"This is the future of learning" +- Slide 15: Call to action—"Available now—let's get your students started" + +### Jobs' Additional Techniques + +**The "One More Thing"**: +- After seemingly concluding +- Introduce surprise fourth element +- Works because you've established the three pattern +- Violates expectation in delightful way +- Use sparingly—once per presentation maximum + +**The Superlative**: +- "This is the best [X] we've ever made" +- "The most important [Y]" +- Bold claims create memorable moments +- Must be backed by evidence + +**The Human Moment**: +- Demo goes wrong → handle gracefully +- Personal story interlude +- Audience interaction +- Breaks script pattern, feels authentic + +--- + +## Framework 3: TED Talk Structure + +### Overview + +TED enforces strict format: 18 minutes maximum, focus on "ideas worth spreading." Thousands of talks have revealed common patterns among the most successful presentations. + +### The Structure + +``` +Part 1: HOOK (30-90 seconds) + └─ Grab attention immediately + +Part 2: PERSONAL CONNECTION (1-3 minutes) + └─ Why this matters to speaker + +Part 3: CORE IDEA (10-12 minutes) + ├─ The insight/discovery + ├─ Evidence and examples + └─ Implications + +Part 4: CALL TO ACTION (2-3 minutes) + └─ What audience should do + +Part 5: MEMORABLE CLOSE (30-60 seconds) + └─ Full circle back to hook OR powerful statement +``` + +### Detailed Breakdown + +**Part 1: The Hook (30-90 seconds)** + +*Purpose: Capture attention in first 30 seconds or lose audience* + +**Hook Types**: + +1. **Provocative Question** + - "What if I told you everything you know about [X] is wrong?" + - Must be genuinely interesting, not rhetorical fluff + - Should connect to core idea + +2. **Surprising Statistic** + - "73% of teachers report..." + - Must be truly surprising, not common knowledge + - Contextual setup in 1-2 sentences max + +3. **Personal Anecdote** + - Brief story (60 seconds max at this stage) + - Must relate directly to topic + - Should be unexpected or emotionally engaging + +4. **Bold Declaration** + - "Everything is about to change" + - "We've been solving the wrong problem" + - Must be backed up—don't make claims you can't support + +5. **Visual Surprise** + - Striking image with no context + - "This is [unexpected thing]" + - Explain connection to topic + +**Critical Elements**: +- Start immediately—no "thanks for having me" preamble +- No agenda slide—jump right in +- Create curiosity gap that demands resolution +- Under 90 seconds total + +**Part 2: Personal Connection (1-3 minutes)** + +*Purpose: Establish credibility and authentic investment* + +**What to Share**: +- How you discovered this topic +- Why it matters personally to you +- Moment of realization or transformation +- Authentic vulnerability (not staged) + +**What NOT to Share**: +- Full resume/credentials (boring) +- Lengthy backstory (self-indulgent) +- Unrelated personal details +- False humility + +**Structure**: +``` +"I first encountered this problem when..." + ↓ +"It challenged everything I believed about..." + ↓ +"That's when I realized..." +``` + +**Example**: +"Five years ago, my daughter came home from school and said, 'I'm stupid at math.' She's brilliant—but the system had convinced her otherwise. That moment launched my obsession with understanding why our brightest students lose confidence. What I discovered shocked me." + +**Part 3: Core Idea (10-12 minutes)** + +*Purpose: Deliver the insight, backed by evidence* + +**Sub-Structure**: + +**A. State the Idea Clearly (1 minute)** +- One sentence summary +- No jargon, plain language +- Memorable phrasing +- Example: "We've been teaching subjects when we should be teaching thinking" + +**B. Explain Why Current Understanding is Wrong/Incomplete (2-3 minutes)** +- What's the prevailing view? +- Why does it persist? +- What are we missing? +- Use specific examples + +**C. Present Your Insight (3-4 minutes)** +- How did you discover this? +- What's the evidence? +- Show, don't just tell +- Use visuals, demos, examples + +**D. Address Skepticism (2-3 minutes)** +- Anticipate objections +- Provide counter-evidence +- Show edge cases or limitations +- Builds credibility through honesty + +**E. Expand Implications (2-3 minutes)** +- If this is true, what else becomes possible? +- Connect to broader themes +- Show systemic impact +- Paint the bigger picture + +**Pacing**: +- Vary between explanation and example +- Use visuals liberally (minimal text) +- Build complexity gradually +- Create "aha" moments through revelation + +**Part 4: Call to Action (2-3 minutes)** + +*Purpose: Make the idea actionable* + +**Not Generic**: +- ❌ "Think about this differently" +- ❌ "Spread the word" +- ❌ "Let's make a change" + +**Specific and Achievable**: +- ✅ "Tomorrow, ask your child what they're curious about, not what they learned" +- ✅ "Visit this website and take the 5-minute assessment" +- ✅ "Share one thing you're uncertain about at your next team meeting" + +**Scaling Calls to Action**: +1. **Individual**: What can one person do? +2. **Collective**: What can we do together? +3. **Systemic**: What policy/institutional change is needed? + +**Format**: +``` +"Here's what I'm asking you to do..." + ↓ +[Specific action] + ↓ +"If enough of us do this..." + ↓ +[Collective impact] +``` + +**Part 5: Memorable Close (30-60 seconds)** + +*Purpose: Leave lasting impression* + +**Closing Techniques**: + +1. **Full Circle** + - Return to opening hook + - Show how it's now understood differently + - "Remember that question I asked? Now you know the answer." + +2. **Vision of Future** + - Paint specific picture of transformed world + - Make it tangible and emotional + - "Imagine a world where..." + +3. **Powerful Quote** + - From relevant source + - Must genuinely add insight, not decorative + - Brief setup, then quote + +4. **Personal Commitment** + - What you're dedicating yourself to + - Inspires through example + - "I'm going to spend the next decade..." + +5. **Direct Challenge** + - Bold ask or provocative question + - Leaves them thinking + - "So I ask you: what are you willing to question?" + +**Critical Elements**: +- NEVER end with Q&A +- NEVER end with "Thank you" +- NEVER trail off or rush +- End with power and intention + +### Application Guidelines + +**Best Used For**: +- Conference keynotes +- Inspirational talks +- Idea-centric presentations (vs. product/sales) +- 15-20 minute time slots +- Presentations that will be recorded/shared + +**Not Recommended For**: +- Internal updates +- Highly technical content +- Sales pitches (too obvious) +- Very short presentations (<10 minutes) + +**Slide Count Implications**: +- Minimum: 8-10 slides +- Typical: 12-18 slides +- Maximum: 25 slides +- Heavy visual focus—many slides with single images + +### Example: Education Innovation + +**Hook (Slide 1)**: Photo of frustrated student. "What if school is making kids less curious, not more?" + +**Personal (Slides 2-3)**: +- Slide 2: Photo of speaker's daughter +- Slide 3: Story of her losing interest in learning + +**Core Idea (Slides 4-12)**: +- Slide 4: "We're teaching answers. We should teach questions." +- Slide 5-6: Research on curiosity and learning +- Slide 7-8: Examples of question-driven classrooms +- Slide 9: Data on outcomes +- Slide 10: Addressing "but standards..." objection +- Slide 11-12: Bigger implications for society + +**Call to Action (Slides 13-14)**: +- Slide 13: "Three questions to ask tomorrow" +- Slide 14: How to join the movement + +**Close (Slide 15)**: Back to daughter's photo. "She's asking questions again. Let's make sure every kid can." + +--- + +## Framework 4: Classic Three-Act Structure + +### Overview + +The oldest storytelling structure, dating back to Aristotle. Still relevant because it mirrors natural narrative arc and audience expectations. + +### The Structure + +``` +ACT 1: SETUP (25% of presentation) + ├─ Introduce "characters" (people, problems, concepts) + ├─ Establish ordinary world/current state + └─ Inciting incident (why this matters now) + +ACT 2: CONFRONTATION (50% of presentation) + ├─ Explore problem deeply + ├─ Failed attempts or challenges + ├─ Rising action and complications + ├─ Midpoint revelation or shift + └─ Escalation to crisis point + +ACT 3: RESOLUTION (25% of presentation) + ├─ Climax (solution or insight) + ├─ Falling action (how it works) + └─ Denouement (new equilibrium) +``` + +### Detailed Breakdown + +**Act 1: Setup (25%)** + +*Purpose: Establish context and create investment* + +**1.1 Ordinary World (5-8% of presentation)** +- Current state of affairs +- Familiar, relatable situation +- Establishes baseline for measuring change +- Example: "For 150 years, education has looked like this..." + +**1.2 Introduction of "Characters" (5-8%)** +- Who is affected? (students, teachers, parents) +- What are their goals and challenges? +- Make audience care about these people +- Example: "Meet Sarah, a third-grade teacher who..." + +**1.3 Inciting Incident (10-12%)** +- The catalyst—why now? +- What changed or was discovered? +- Creates urgency and forward momentum +- Example: "Then COVID-19 forced the entire system online overnight..." + +**Act 2: Confrontation (50%)** + +*Purpose: Explore depth, build tension, earn the resolution* + +**2.1 Exploring the Problem (10-15%)** +- Dig deeper into challenges +- Show why obvious solutions don't work +- Build complexity and nuance +- Example: "Virtual learning exposed three fundamental flaws..." + +**2.2 Failed Attempts / Obstacles (10-15%)** +- What's been tried? +- Why didn't it work? +- Shows understanding of difficulty +- Builds credibility +- Example: "Districts spent millions on tablets. Engagement actually decreased..." + +**2.3 Midpoint Shift (5-8%)** +- New information or perspective +- "What we discovered changed everything" +- Turning point in understanding +- Example: "But one school tried something different..." + +**2.4 Escalating Complexity (10-15%)** +- Deeper implications emerge +- Stakes get higher +- "It's not just about X, it's about Y" +- Example: "This isn't a technology problem—it's an identity crisis for educators..." + +**2.5 Crisis Point (5-8%)** +- Moment of maximum tension +- "We have to choose" +- Forces decision or action +- Example: "We can keep pretending this works, or we can reimagine education entirely" + +**Act 3: Resolution (25%)** + +*Purpose: Deliver payoff, show path forward* + +**3.1 Climax (8-10%)** +- The solution, insight, or breakthrough +- Moment of greatest revelation +- "Here's what actually works" +- Example: "When we let students drive their own learning..." + +**3.2 How It Works (10-12%)** +- Practical implementation +- Evidence and examples +- Concrete details +- Example: "Here's what it looks like in practice..." + +**3.3 New Equilibrium (7-8%)** +- What's different now? +- How has world transformed? +- Call to action +- Future vision +- Example: "This is education for 2025 and beyond. Here's how we get there..." + +### Application Guidelines + +**Best Used For**: +- Story-driven presentations +- Case studies +- Transformation narratives +- Problem-solution structures +- Medium to long presentations (20-45 minutes) + +**Not Recommended For**: +- Pure data presentations +- Quick updates +- Highly technical content without narrative +- Very short presentations (<15 minutes) + +**Slide Count Implications**: +- Short version (20 min): 15-20 slides + - Act 1: 4-5 slides + - Act 2: 8-10 slides + - Act 3: 4-5 slides +- Long version (45 min): 25-35 slides + - Act 1: 6-9 slides + - Act 2: 13-18 slides + - Act 3: 6-9 slides + +--- + +## Framework Comparison Matrix + +| Framework | Duration | Slide Count | Best For | Emotional Arc | Complexity | +|-----------|----------|-------------|----------|---------------|------------| +| **Sparkline** | 20-30 min | 18-25 | Keynotes, vision casting | High peaks and valleys | High | +| **Rule of Three** | 15-30 min | 12-18 | Product launches, demos | Steady building | Medium | +| **TED Structure** | 15-20 min | 12-18 | Idea-centric, inspirational | Single climactic peak | Medium-High | +| **Three-Act** | 20-45 min | 15-35 | Case studies, narratives | Rising to climax, resolution | High | + +--- + +## Choosing the Right Framework + +### Decision Tree + +**Start Here**: What's your primary goal? + +**If INSPIRE/TRANSFORM**: +- Duration 20+ minutes → Sparkline +- Duration <20 minutes → TED Structure + +**If PERSUADE/SELL**: +- Product-focused → Rule of Three +- Story-driven → Three-Act Structure + +**If INFORM/EDUCATE**: +- Problem-solution → Three-Act Structure +- Feature demonstration → Rule of Three + +**If QUICK UPDATE**: +- None of these—use simple structure +- Opening → Key Points → Close + +### Hybrid Approaches + +You can combine frameworks: + +**Sparkline + Rule of Three**: +- Use sparkline emotional arc +- Organize "what could be" sections into three main points +- Example: Three visions of future, each contrasted with reality + +**TED + Three-Act**: +- Hook and personal connection (Act 1) +- Core idea as confrontation (Act 2) +- Call to action as resolution (Act 3) +- Natural alignment + +**Rule of Three + Sparkline**: +- Three main features/points +- Each point uses mini sparkline (is/could be contrast) +- Builds to overall transformation + +--- + +## Common Mistakes Across All Frameworks + +### Structural Errors + +1. **Starting with agenda slide** + - Kills momentum + - Signals boring presentation + - Better: Jump right into hook + +2. **No clear inciting incident** + - Presentation lacks urgency + - "Why now?" is unclear + - Audience questions relevance + +3. **Unearned climax** + - Big reveal without proper buildup + - Audience isn't prepared to appreciate it + - Falls flat + +4. **Multiple climaxes** + - Trying to make everything important + - Dilutes actual peak moments + - Confuses audience + +5. **Weak ending** + - Trailing off + - "Any questions?" as close + - Not landing the message + +### Content Errors + +1. **Too much setup** + - Spending 40% on background + - Audience loses patience + - Core message gets rushed + +2. **No conflict/tension** + - All smooth sailing + - Boring, not engaging + - No stakes + +3. **Ignoring obstacles** + - Presenting solution without acknowledging challenges + - Seems naive or dishonest + - Reduces credibility + +4. **Missing emotional beats** + - All facts, no feeling + - Cognitively exhausting + - Forgettable + +--- + +## Advanced Techniques + +### The Nested Story + +Embed smaller stories within main framework: + +``` +Main Framework: Three-Act Structure + Act 2 includes: + → Customer story (mini three-act) + → Team journey (mini three-act) + → Product development (mini three-act) +``` + +Each nested story has own arc but serves larger narrative. + +### The Recurring Motif + +Introduce element in opening, revisit throughout: + +- Physical object that represents theme +- Phrase that gains new meaning +- Image that appears multiple times +- Question that gets progressively answered + +Example: "What makes a teacher great?" asked at start, explored through presentation, answered with new depth at end. + +### The Parallel Structure + +Tell two stories simultaneously that converge: + +``` +Story A (Problem): Traditional education path +Story B (Solution): New approach + ↓ ↓ +Converge: Shows contrast +``` + +Slides alternate between Story A and Story B until they meet. + +### The Revelation Sequence + +Withhold key information, reveal progressively: + +``` +Slide 1: "We tested 10 approaches" +Slide 2: "9 failed" +Slide 3: "But one..." +Slide 4: [The one that worked] +``` + +Builds suspense through controlled information release. + +--- + +## Testing Your Structure + +### Before Finalizing + +**The Elevator Test**: +- Can you summarize arc in 30 seconds? +- If not, structure is too complex + +**The Emotional Check**: +- Map emotional intensity across slides +- Should have valleys and peaks, not flat line +- Highest peak should be near end (not middle) + +**The "So What?" Test**: +- After each major section: "So what?" +- If you can't answer, section doesn't earn its place + +**The Memory Test**: +- What will audience remember 24 hours later? +- Structure should make key points memorable +- If everything is equally important, nothing is + +### After First Rehearsal + +**The Timing Test**: +- Does reality match planned percentages? +- If Act 1 is taking 40% of time, rebalance + +**The Flow Test**: +- Do transitions feel natural? +- Is there a clear through-line? +- Can you feel the momentum? + +**The Engagement Test**: +- Present to test audience +- Where do they lean in? +- Where do they check out? +- Adjust structure accordingly + +--- + +This comprehensive guide to story frameworks provides the architectural foundation for presentations that aren't just informative—they're transformative. Master these structures, and you'll never wonder "what comes next?" again. diff --git a/skills/presentation-master/principles/validation-rules.md b/skills/presentation-master/principles/validation-rules.md new file mode 100644 index 0000000..d5fe153 --- /dev/null +++ b/skills/presentation-master/principles/validation-rules.md @@ -0,0 +1,149 @@ +# Validation Rules & Scoring System + +Automatic quality assessment for presentations. + +## Scoring Formula (0-100) + +### Simplicity (10 points) +- **Word count per slide**: 0-3 words = 10pts, 4-6 words = 8pts, 7-10 words = 5pts, >10 words = 0pts +- **Visual clutter**: Single element = 10pts, 2-3 elements = 8pts, 4-5 elements = 5pts, >5 elements = 0pts + +### Visual Dominance (10 points) +- **Image quality**: All high-res = 10pts, some low-res = 5pts, no images = 0pts +- **Text-to-visual ratio**: 20/80 or better = 10pts, 50/50 = 5pts, 80/20 = 0pts + +### Story Structure (10 points) +- **Narrative arc**: Clear beginning/middle/end = 10pts, partial = 5pts, none = 0pts +- **Emotional beats**: 3+ moments = 10pts, 1-2 moments = 5pts, none = 0pts + +### One Idea Per Slide (10 points) +- **Concept clarity**: All slides single-concept = 10pts, most = 7pts, mixed = 3pts, confused = 0pts + +### Typography (8 points) +- **Font size**: All 36pt+ = 8pts, all 30pt+ = 6pts, some <30pt = 2pts, any <24pt = 0pts +- **Consistency**: 1 font family = 8pts, 2 families = 6pts, 3+ families = 0pts + +### Layout (7 points) +- **Visual hierarchy**: Clear focal points = 7pts, somewhat clear = 4pts, unclear = 0pts +- **Whitespace**: 40%+ = 7pts, 20-40% = 4pts, <20% = 0pts +- **Alignment**: All aligned = 7pts, mostly = 4pts, inconsistent = 0pts + +### Color/Contrast (7 points) +- **Readability**: 7:1+ contrast = 7pts, 4.5:1+ = 5pts, <4.5:1 = 0pts +- **Consistency**: Single palette = 7pts, mixed = 3pts, chaotic = 0pts + +### Media Quality (8 points) +- **Image resolution**: All 2K+ = 8pts, all 1K+ = 6pts, some low-res = 2pts +- **Relevance**: All relevant = 8pts, mostly = 5pts, decorative = 0pts + +### Cognitive Load (20 points) +- **Mayer's 12 principles adherence**: 10-12 = 20pts, 7-9 = 15pts, 4-6 = 10pts, 1-3 = 5pts, 0 = 0pts + +### Data Integrity (10 points, if applicable) +- **Lie factor**: 0.95-1.05 = 10pts, 0.90-1.10 = 7pts, 0.80-1.20 = 3pts, outside = 0pts +- **Data-ink ratio**: Maximized = 10pts, good = 7pts, poor = 3pts, terrible = 0pts + +## Critical Violations (Auto-Fail) + +These cause immediate score reduction or failure: + +1. **Font size < 30pt** → -20 points +2. **>10 core concepts** → -15 points (Kawasaki violation) +3. **Bullet points detected** → -10 points per slide +4. **Paragraphs (>2 sentences)** → -10 points per slide +5. **Contrast ratio <4.5:1** → -15 points +6. **Default template detected** → -20 points + +## Warning Flags + +These reduce score but don't fail: + +1. **>6 words per slide** → -2 points per violation (Godin standard) +2. **>15 slides for 20-min presentation** → -5 points +3. **No images** → -10 points +4. **Text-heavy slides (>3 lines)** → -3 points per slide +5. **Inconsistent fonts (>2 families)** → -5 points +6. **Low-res images** → -3 points per image + +## Score Interpretation + +- **90-100**: Exceptional - TED/Keynote quality +- **80-89**: Excellent - Professional standard +- **70-79**: Good - Solid presentation +- **60-69**: Acceptable - Needs improvement +- **<60**: Poor - Major revisions needed + +## Automated Checks (JavaScript) + +```javascript +function validatePresentation(slides) { + let score = 0; + const issues = []; + + // Check each slide + slides.forEach((slide, i) => { + const wordCount = slide.text.split(' ').length; + const fontSize = slide.minFontSize; + const hasBullets = slide.text.includes('•') || slide.text.includes('-'); + + // Word count scoring + if (wordCount <= 3) score += 10 / slides.length; + else if (wordCount <= 6) score += 8 / slides.length; + else if (wordCount <= 10) score += 5 / slides.length; + else issues.push(`Slide ${i+1}: ${wordCount} words (recommend ≤6)`); + + // Font size critical check + if (fontSize < 30) { + score -= 20; + issues.push(`CRITICAL: Slide ${i+1} has ${fontSize}pt font (minimum 30pt)`); + } + + // Bullet point check + if (hasBullets) { + score -= 10; + issues.push(`CRITICAL: Slide ${i+1} has bullet points (use individual slides)`); + } + }); + + return { score: Math.max(0, Math.min(100, score)), issues }; +} +``` + +## Quality Report Template + +```markdown +# Presentation Quality Report + +**Overall Score**: {score}/100 +**Status**: {Exceptional|Excellent|Good|Acceptable|Poor} + +## Strengths +- {List what scores well} + +## Critical Issues +- {Font size violations} +- {Bullet points} +- {Contrast problems} + +## Warnings +- {Word count} +- {Slide count} +- {Consistency issues} + +## Recommendations +1. {Highest priority fix} +2. {Second priority} +3. {Third priority} + +## Score Breakdown +- Simplicity: {score}/10 +- Visual Dominance: {score}/10 +- Story Structure: {score}/10 +- One Idea/Slide: {score}/10 +- Typography: {score}/8 +- Layout: {score}/7 +- Color/Contrast: {score}/7 +- Media Quality: {score}/8 +- Cognitive Load: {score}/20 +- Data Integrity: {score}/10 (if applicable) +``` diff --git a/skills/presentation-master/scripts/analyze-context.js b/skills/presentation-master/scripts/analyze-context.js new file mode 100644 index 0000000..4c95fe0 --- /dev/null +++ b/skills/presentation-master/scripts/analyze-context.js @@ -0,0 +1,370 @@ +#!/usr/bin/env bun + +/** + * Presentation Context Analyzer + * + * Analyzes topic, audience, duration, purpose to detect presentation type + * and recommend appropriate story framework. + * + * Usage: + * bun analyze-context.js --topic "Cybersecurity Trends" --audience "School Board" --duration "15min" --purpose "inform" + * + * Output: JSON with presentation type, recommended framework, pattern distribution + */ + +const PRESENTATION_TYPES = { + BOARD_UPDATE: { + name: 'board-update', + indicators: ['board', 'executive', 'update', 'quarterly', 'status', 'report'], + characteristics: { + audience_technical: 'low', + focus: 'data-driven', + primary_goal: 'inform + recommend', + typical_duration: '15-20min' + }, + pattern_distribution: { + 'data-viz': 0.40, + 'visual-caption': 0.30, + 'transition': 0.20, + 'title': 0.10 + }, + recommended_frameworks: ['classic-three-act', 'rule-of-three'] + }, + + KEYNOTE: { + name: 'keynote', + indicators: ['keynote', 'conference', 'inspire', 'vision', 'future', 'transform'], + characteristics: { + audience_technical: 'mixed', + focus: 'inspirational', + primary_goal: 'shift perspective', + typical_duration: '20-30min' + }, + pattern_distribution: { + 'big-idea': 0.40, + 'visual-caption': 0.30, + 'title': 0.20, + 'transition': 0.10 + }, + recommended_frameworks: ['sparkline', 'rule-of-three', 'ted'] + }, + + TRAINING: { + name: 'training', + indicators: ['training', 'workshop', 'tutorial', 'learn', 'how-to', 'guide'], + characteristics: { + audience_technical: 'variable', + focus: 'educational', + primary_goal: 'teach + practice', + typical_duration: '30-60min' + }, + pattern_distribution: { + 'process': 0.40, + 'data-viz': 0.30, + 'visual-caption': 0.20, + 'title': 0.10 + }, + recommended_frameworks: ['classic-three-act'] + }, + + PITCH: { + name: 'pitch', + indicators: ['pitch', 'proposal', 'investment', 'funding', 'sell', 'convince'], + characteristics: { + audience_technical: 'mixed', + focus: 'persuasive', + primary_goal: 'convince + action', + typical_duration: '10-20min' + }, + pattern_distribution: { + 'data-viz': 0.30, + 'big-idea': 0.30, + 'visual-caption': 0.25, + 'title-transition': 0.15 + }, + recommended_frameworks: ['rule-of-three', 'classic-three-act'] + }, + + TED_STYLE: { + name: 'ted-style', + indicators: ['ted', 'idea', 'story', 'personal', 'change the world'], + characteristics: { + audience_technical: 'general', + focus: 'idea-centric', + primary_goal: 'inspire + spread idea', + typical_duration: '15-20min' + }, + pattern_distribution: { + 'big-idea': 0.35, + 'visual-caption': 0.35, + 'transition': 0.20, + 'title': 0.10 + }, + recommended_frameworks: ['ted'] + } +}; + +const STORY_FRAMEWORKS = { + 'sparkline': { + name: "Nancy Duarte's Sparkline", + duration: '20-30min', + slides: '18-25', + best_for: ['keynote', 'ted-style'], + structure: 'Alternate "what is" (reality) with "what could be" (aspiration)', + complexity: 'high' + }, + + 'rule-of-three': { + name: "Steve Jobs' Rule of Three", + duration: '15-30min', + slides: '12-18', + best_for: ['keynote', 'pitch', 'board-update'], + structure: 'Three main sections, three points per section', + complexity: 'medium' + }, + + 'ted': { + name: 'TED Talk Structure', + duration: '15-20min', + slides: '12-18', + best_for: ['ted-style', 'keynote'], + structure: 'Hook → Personal → Core Idea → Call to Action → Close', + complexity: 'medium' + }, + + 'classic-three-act': { + name: 'Classic Three-Act Structure', + duration: '20-45min', + slides: '15-35', + best_for: ['training', 'board-update', 'pitch'], + structure: 'Setup (25%) → Confrontation (50%) → Resolution (25%)', + complexity: 'low' + } +}; + +function parseDuration(durationStr) { + // Parse strings like "15min", "20 minutes", "1 hour", "45m" + const matches = durationStr.toLowerCase().match(/(\d+)\s*(min|minute|minutes|m|hour|hours|h)/); + if (!matches) return null; + + const value = parseInt(matches[1]); + const unit = matches[2]; + + if (unit.startsWith('h')) { + return value * 60; // convert to minutes + } + return value; +} + +function detectPresentationType(topic, audience, purpose) { + const combined = `${topic} ${audience} ${purpose}`.toLowerCase(); + const scores = {}; + + for (const [key, type] of Object.entries(PRESENTATION_TYPES)) { + let score = 0; + + // Check for indicator keywords + for (const indicator of type.indicators) { + if (combined.includes(indicator)) { + score += 10; + } + } + + scores[type.name] = score; + } + + // Find highest scoring type + const sortedTypes = Object.entries(scores).sort((a, b) => b[1] - a[1]); + + if (sortedTypes[0][1] === 0) { + // No clear match, default based on purpose + if (purpose.includes('teach') || purpose.includes('train')) return 'training'; + if (purpose.includes('inspire') || purpose.includes('motivate')) return 'keynote'; + if (purpose.includes('convince') || purpose.includes('sell')) return 'pitch'; + return 'board-update'; // conservative default + } + + return sortedTypes[0][0]; +} + +function recommendFrameworks(presentationType, durationMinutes) { + const type = Object.values(PRESENTATION_TYPES).find(t => t.name === presentationType); + if (!type) return []; + + // Get recommended frameworks for this type + const recommendations = type.recommended_frameworks.map(fw => { + const framework = STORY_FRAMEWORKS[fw]; + + // Parse framework duration range + const durationMatch = framework.duration.match(/(\d+)-(\d+)min/); + if (!durationMatch) return { ...framework, key: fw, fit_score: 50 }; + + const minDuration = parseInt(durationMatch[1]); + const maxDuration = parseInt(durationMatch[2]); + + // Score based on duration fit + let fit_score = 50; + if (durationMinutes >= minDuration && durationMinutes <= maxDuration) { + fit_score = 100; + } else if (durationMinutes < minDuration) { + fit_score = Math.max(0, 100 - ((minDuration - durationMinutes) * 5)); + } else { + fit_score = Math.max(0, 100 - ((durationMinutes - maxDuration) * 5)); + } + + return { + key: fw, + ...framework, + fit_score + }; + }); + + // Sort by fit score + return recommendations.sort((a, b) => b.fit_score - a.fit_score); +} + +function estimateSlideCount(durationMinutes, presentationType) { + // Guy Kawasaki: 10 slides for 20 minutes = 0.5 slides/min + // Adjust based on presentation type + + const rates = { + 'board-update': 0.5, // More data-heavy, slower pace + 'keynote': 0.7, // More visuals, faster pace + 'training': 0.4, // More explanation needed + 'pitch': 0.6, // Balanced + 'ted-style': 0.8 // Fast-paced, visual + }; + + const rate = rates[presentationType] || 0.5; + const baseCount = Math.round(durationMinutes * rate); + + // Kawasaki's hard limit: max 10 core concepts + // But we can have transition/title slides + const maxCoreSlides = 10; + const coreSlides = Math.min(baseCount, maxCoreSlides); + const supportSlides = Math.ceil(coreSlides * 0.3); // 30% support slides + + return { + total: coreSlides + supportSlides, + core: coreSlides, + support: supportSlides, + recommendation: coreSlides + supportSlides <= 15 ? 'optimal' : 'consider-simplifying' + }; +} + +function analyzeAudience(audienceStr) { + const lower = audienceStr.toLowerCase(); + + // Technical level + let technical_level = 'medium'; + if (lower.match(/board|executive|c-suite|non-technical/)) { + technical_level = 'low'; + } else if (lower.match(/engineer|developer|technical|expert|specialist/)) { + technical_level = 'high'; + } + + // Decision-making power + let decision_power = 'medium'; + if (lower.match(/board|executive|ceo|cio|cto|director|vp/)) { + decision_power = 'high'; + } else if (lower.match(/staff|team|individual contributor|ic/)) { + decision_power = 'low'; + } + + // Size + let size = 'medium'; + if (lower.match(/small|intimate|1:1|one-on-one/)) { + size = 'small'; + } else if (lower.match(/large|conference|hundreds|auditorium/)) { + size = 'large'; + } + + return { + technical_level, + decision_power, + size, + recommendations: { + font_size: size === 'large' ? '42pt+' : '36pt+', + detail_level: technical_level === 'high' ? 'can-include-technical-details' : 'avoid-jargon', + call_to_action: decision_power === 'high' ? 'specific-next-steps' : 'awareness-building' + } + }; +} + +function generateAnalysis(args) { + const topic = args.topic || ''; + const audience = args.audience || ''; + const duration = args.duration || '20min'; + const purpose = args.purpose || ''; + + const durationMinutes = parseDuration(duration); + const presentationType = detectPresentationType(topic, audience, purpose); + const typeDetails = Object.values(PRESENTATION_TYPES).find(t => t.name === presentationType); + const frameworks = recommendFrameworks(presentationType, durationMinutes); + const slideEstimate = estimateSlideCount(durationMinutes, presentationType); + const audienceAnalysis = analyzeAudience(audience); + + return { + input: { + topic, + audience, + duration, + purpose + }, + analysis: { + presentation_type: presentationType, + type_characteristics: typeDetails.characteristics, + audience_analysis: audienceAnalysis, + duration_minutes: durationMinutes, + slide_estimate: slideEstimate, + pattern_distribution: typeDetails.pattern_distribution + }, + recommendations: { + primary_framework: frameworks[0], + alternative_frameworks: frameworks.slice(1), + key_principles: [ + 'Maximum 6 words per slide (Seth Godin)', + `Font size minimum: ${audienceAnalysis.recommendations.font_size}`, + `${slideEstimate.core} core concepts maximum (Guy Kawasaki)`, + 'One idea per slide', + 'Visual dominance over text' + ] + }, + warnings: [ + slideEstimate.recommendation === 'consider-simplifying' + ? `⚠️ ${slideEstimate.total} slides may be too many - consider simplifying to ${Math.min(slideEstimate.core, 10)} core concepts` + : null, + durationMinutes > 30 + ? '⚠️ Presentations >30min risk losing audience attention - consider breaking into sections' + : null, + audienceAnalysis.technical_level === 'low' && topic.toLowerCase().match(/technical|technology|ai|software/) + ? '⚠️ Non-technical audience + technical topic = extra emphasis on visual metaphors' + : null + ].filter(w => w !== null) + }; +} + +// CLI Interface +function main() { + const args = {}; + + for (let i = 2; i < process.argv.length; i += 2) { + const key = process.argv[i].replace(/^--/, ''); + const value = process.argv[i + 1]; + args[key] = value; + } + + if (!args.topic && !args.audience && !args.duration) { + console.error('Usage: bun analyze-context.js --topic "Topic" --audience "Audience" --duration "15min" [--purpose "Purpose"]'); + process.exit(1); + } + + const analysis = generateAnalysis(args); + console.log(JSON.stringify(analysis, null, 2)); +} + +if (import.meta.main) { + main(); +} + +export { generateAnalysis, detectPresentationType, recommendFrameworks, estimateSlideCount, analyzeAudience }; diff --git a/skills/presentation-master/scripts/suggest-images.js b/skills/presentation-master/scripts/suggest-images.js new file mode 100644 index 0000000..1a993c8 --- /dev/null +++ b/skills/presentation-master/scripts/suggest-images.js @@ -0,0 +1,342 @@ +#!/usr/bin/env bun + +/** + * Visual Recommendation Engine + * + * Analyzes slide content and recommends visual types and generation prompts + * for the image-gen skill. + * + * Usage: + * bun suggest-images.js --slides slides.json --presentation-id "cyber-2025" + * + * Output: JSON with image recommendations, prompts, cost estimates + */ + +const IMAGE_COSTS = { + '1K': 0.065, // 1024x1024 + '2K': 0.13, // 2048x2048 + '4K': 0.24 // 4096x4096 +}; + +const VISUAL_TYPES = { + INFOGRAPHIC: { + name: 'infographic', + best_for: ['statistics', 'comparisons', 'processes', 'timelines'], + style_keywords: ['clean', 'modern', 'professional', 'data-driven', 'minimalist'], + default_resolution: '2K', + prompt_template: 'Clean, modern infographic showing {concept}. Minimalist design, professional color palette, clear visual hierarchy. {specifics}. High contrast, data-focused, no text.' + }, + + CONCEPTUAL: { + name: 'conceptual', + best_for: ['abstract ideas', 'metaphors', 'themes', 'emotions'], + style_keywords: ['metaphorical', 'symbolic', 'artistic', 'thought-provoking'], + default_resolution: '2K', + prompt_template: 'Conceptual image representing {concept}. Symbolic, thought-provoking visual metaphor. {specifics}. Artistic but professional, high quality, suitable for business presentation.' + }, + + REALISTIC: { + name: 'realistic', + best_for: ['examples', 'scenarios', 'people', 'places', 'objects'], + style_keywords: ['photographic', 'realistic', 'professional', 'high-quality'], + default_resolution: '2K', + prompt_template: 'Professional photograph of {concept}. Realistic, high-quality, well-lit. {specifics}. Commercial photography style, suitable for corporate presentation.' + }, + + DIAGRAM: { + name: 'diagram', + best_for: ['technical concepts', 'architectures', 'flows', 'relationships'], + style_keywords: ['technical', 'schematic', 'architectural', 'structured'], + default_resolution: '2K', + prompt_template: 'Clean technical diagram illustrating {concept}. {specifics}. Professional, minimal color, clear connections, no labels or text.' + }, + + DATA_VIZ: { + name: 'data-visualization', + best_for: ['trends', 'growth', 'decline', 'distributions', 'correlations'], + style_keywords: ['chart', 'graph', 'visualization', 'quantitative'], + default_resolution: '2K', + prompt_template: 'Modern data visualization showing {concept}. {specifics}. Clean design, professional color scheme, Tufte-style minimalism, no grid lines or labels.' + }, + + ABSTRACT: { + name: 'abstract', + best_for: ['innovation', 'transformation', 'future', 'technology'], + style_keywords: ['abstract', 'modern', 'technological', 'futuristic'], + default_resolution: '2K', + prompt_template: 'Abstract visual representing {concept}. Modern, technological feel. {specifics}. Clean, professional, suitable for corporate presentation.' + } +}; + +const CONTENT_PATTERNS = { + // Numeric indicators + numeric: { + patterns: [/\d+%/, /\$\d+/, /\d+[KMB]/, /\d+ (percent|million|billion|thousand)/i], + recommended_types: ['infographic', 'data-visualization'] + }, + + // Comparison indicators + comparison: { + patterns: [/vs\.?/i, /versus/i, /compared to/i, /before.*after/i, /old.*new/i], + recommended_types: ['infographic', 'data-visualization'] + }, + + // Process indicators + process: { + patterns: [/step/i, /phase/i, /stage/i, /process/i, /workflow/i, /pipeline/i], + recommended_types: ['diagram', 'infographic'] + }, + + // Time indicators + timeline: { + patterns: [/timeline/i, /history/i, /evolution/i, /\d{4}/, /past.*future/i], + recommended_types: ['infographic', 'diagram'] + }, + + // Abstract concepts + abstract: { + patterns: [/future/i, /innovation/i, /transform/i, /vision/i, /imagine/i, /potential/i], + recommended_types: ['conceptual', 'abstract'] + }, + + // People/scenarios + human: { + patterns: [/people/i, /user/i, /student/i, /teacher/i, /team/i, /customer/i], + recommended_types: ['realistic', 'conceptual'] + }, + + // Technical + technical: { + patterns: [/architecture/i, /system/i, /infrastructure/i, /network/i, /api/i], + recommended_types: ['diagram', 'abstract'] + } +}; + +function analyzeSlideContent(slide) { + const content = `${slide.title || ''} ${slide.text || ''} ${slide.notes || ''}`.toLowerCase(); + + // Detect patterns + const detectedPatterns = []; + for (const [patternName, pattern] of Object.entries(CONTENT_PATTERNS)) { + for (const regex of pattern.patterns) { + if (regex.test(content)) { + detectedPatterns.push({ + pattern: patternName, + recommended_types: pattern.recommended_types + }); + break; + } + } + } + + return detectedPatterns; +} + +function selectVisualType(patterns, slidePattern) { + // If no patterns detected, use slide pattern to guide + if (patterns.length === 0) { + switch (slidePattern) { + case 'data-viz': + return VISUAL_TYPES.DATA_VIZ; + case 'process': + case 'timeline': + return VISUAL_TYPES.DIAGRAM; + case 'big-idea': + return VISUAL_TYPES.CONCEPTUAL; + default: + return VISUAL_TYPES.REALISTIC; + } + } + + // Count type recommendations + const typeCounts = {}; + for (const p of patterns) { + for (const type of p.recommended_types) { + typeCounts[type] = (typeCounts[type] || 0) + 1; + } + } + + // Get highest scoring type + const sorted = Object.entries(typeCounts).sort((a, b) => b[1] - a[1]); + const typeName = sorted[0][0]; + + // Find matching visual type + for (const visualType of Object.values(VISUAL_TYPES)) { + if (visualType.name === typeName) { + return visualType; + } + } + + return VISUAL_TYPES.CONCEPTUAL; // fallback +} + +function extractConcepts(slide) { + // Extract key concepts from slide content + const title = slide.title || ''; + const text = slide.text || ''; + + // Primary concept is the title (simplified) + const concept = title.replace(/[?!.]/g, '').trim(); + + // Secondary details from text + const specifics = text + ? text.split(/[.!?]/).slice(0, 2).join('. ').trim() + : ''; + + return { concept, specifics }; +} + +function generatePrompt(visualType, slide) { + const { concept, specifics } = extractConcepts(slide); + + // Use template + let prompt = visualType.prompt_template + .replace('{concept}', concept) + .replace('{specifics}', specifics); + + // Add brand context if available + if (slide.brand) { + if (slide.brand === 'psd') { + prompt += ' Peninsula School District brand: teal/green color palette (#6CA18A), professional education context.'; + } else if (slide.brand === 'personal') { + prompt += ' Modern, clean aesthetic.'; + } + } + + return prompt; +} + +function estimateCost(imageCount, resolution = '2K') { + const perImage = IMAGE_COSTS[resolution]; + return { + per_image: perImage, + total: perImage * imageCount, + resolution, + currency: 'USD' + }; +} + +function shouldGenerateImage(slide) { + // Skip image generation for certain patterns + if (slide.pattern === 'title' && slide.index === 0) { + return false; // Title slide often doesn't need generated image + } + + if (slide.pattern === 'transition') { + return false; // Transitions are usually text-only + } + + if (slide.pattern === 'big-idea' && !slide.needs_visual) { + return false; // Some big ideas are typography-only + } + + return true; +} + +function generateRecommendations(slides, presentationId, options = {}) { + const brand = options.brand || null; + const resolution = options.resolution || '2K'; + const autoInclude = options.auto_include !== false; + + const recommendations = []; + + for (let i = 0; i < slides.length; i++) { + const slide = { ...slides[i], index: i, brand }; + + if (!shouldGenerateImage(slide)) { + recommendations.push({ + slide_index: i, + slide_title: slide.title, + recommendation: 'no-image-needed', + reason: `Pattern '${slide.pattern}' typically doesn't require generated image` + }); + continue; + } + + // Analyze content + const patterns = analyzeSlideContent(slide); + const visualType = selectVisualType(patterns, slide.pattern); + + // Generate prompt + const prompt = generatePrompt(visualType, slide); + + // Generate filename + const slideNum = String(i + 1).padStart(2, '0'); + const slugTitle = slide.title + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/^-+|-+$/g, '') + .substring(0, 40); + const filename = `${presentationId}-slide-${slideNum}-${slugTitle}.png`; + + recommendations.push({ + slide_index: i, + slide_title: slide.title, + slide_pattern: slide.pattern, + visual_type: visualType.name, + prompt, + filename, + resolution, + auto_include: autoInclude, + confidence: patterns.length > 0 ? 'high' : 'medium' + }); + } + + // Calculate costs + const imagesToGenerate = recommendations.filter(r => r.recommendation !== 'no-image-needed'); + const costEstimate = estimateCost(imagesToGenerate.length, resolution); + + return { + presentation_id: presentationId, + total_slides: slides.length, + images_recommended: imagesToGenerate.length, + cost_estimate: costEstimate, + recommendations, + summary: { + by_type: imagesToGenerate.reduce((acc, r) => { + acc[r.visual_type] = (acc[r.visual_type] || 0) + 1; + return acc; + }, {}), + high_confidence: imagesToGenerate.filter(r => r.confidence === 'high').length, + medium_confidence: imagesToGenerate.filter(r => r.confidence === 'medium').length + } + }; +} + +// CLI Interface +function main() { + const args = {}; + + for (let i = 2; i < process.argv.length; i++) { + if (process.argv[i].startsWith('--')) { + const key = process.argv[i].replace(/^--/, ''); + const value = process.argv[i + 1]; + args[key] = value; + i++; + } + } + + if (!args.slides || !args['presentation-id']) { + console.error('Usage: bun suggest-images.js --slides slides.json --presentation-id "cyber-2025" [--brand psd] [--resolution 2K]'); + process.exit(1); + } + + // Read slides from file + const fs = require('fs'); + const slidesData = JSON.parse(fs.readFileSync(args.slides, 'utf-8')); + const slides = Array.isArray(slidesData) ? slidesData : slidesData.slides; + + const options = { + brand: args.brand || null, + resolution: args.resolution || '2K' + }; + + const recommendations = generateRecommendations(slides, args['presentation-id'], options); + console.log(JSON.stringify(recommendations, null, 2)); +} + +if (import.meta.main) { + main(); +} + +export { generateRecommendations, analyzeSlideContent, selectVisualType, generatePrompt, estimateCost }; diff --git a/skills/presentation-master/scripts/validate-presentation.js b/skills/presentation-master/scripts/validate-presentation.js new file mode 100644 index 0000000..8d3afab --- /dev/null +++ b/skills/presentation-master/scripts/validate-presentation.js @@ -0,0 +1,549 @@ +#!/usr/bin/env bun + +/** + * Presentation Quality Validator + * + * Scores presentations 0-100 against best practices from presentation masters. + * Implements validation rules from principles/validation-rules.md + * + * Usage: + * bun validate-presentation.js --presentation presentation.json + * + * Output: JSON with score, breakdown, critical issues, warnings, recommendations + */ + +const SCORING_WEIGHTS = { + simplicity: 10, + visual_dominance: 10, + story_structure: 10, + one_idea_per_slide: 10, + typography: 8, + layout: 7, + color_contrast: 7, + media_quality: 8, + cognitive_load: 20, + data_integrity: 10 +}; + +const CRITICAL_VIOLATIONS = { + font_too_small: { penalty: -20, threshold: 30 }, + too_many_concepts: { penalty: -15, threshold: 10 }, + bullet_points: { penalty: -10 }, + paragraphs: { penalty: -10 }, + poor_contrast: { penalty: -15, threshold: 4.5 }, + default_template: { penalty: -20 } +}; + +const WARNING_FLAGS = { + too_many_words: { penalty: -2, threshold: 6 }, + too_many_slides: { penalty: -5, ratio: 0.75 }, + no_images: { penalty: -10 }, + text_heavy: { penalty: -3, threshold: 3 }, + inconsistent_fonts: { penalty: -5, threshold: 2 }, + low_res_images: { penalty: -3 } +}; + +function countWords(text) { + if (!text) return 0; + return text.trim().split(/\s+/).filter(w => w.length > 0).length; +} + +function detectBulletPoints(text) { + if (!text) return false; + return /[•\-*]\s/.test(text) || /^\s*[\d]+\.\s/m.test(text); +} + +function detectParagraphs(text) { + if (!text) return false; + const sentences = text.split(/[.!?]/).filter(s => s.trim().length > 0); + return sentences.length > 2; +} + +function estimateContrastRatio(slide) { + // Simplified contrast estimation + // In real implementation, would analyze actual colors + if (slide.contrast_ratio) return slide.contrast_ratio; + + // Conservative default + return 7.0; +} + +function countElements(slide) { + let elements = 0; + if (slide.title) elements++; + if (slide.text) elements++; + if (slide.image) elements++; + if (slide.chart) elements++; + return elements; +} + +function scoreSimplicity(slides) { + let score = 0; + const maxScore = SCORING_WEIGHTS.simplicity; + + for (const slide of slides) { + const wordCount = countWords(slide.text); + const elements = countElements(slide); + + // Word count scoring + let wordScore = 0; + if (wordCount <= 3) wordScore = 10; + else if (wordCount <= 6) wordScore = 8; + else if (wordCount <= 10) wordScore = 5; + else wordScore = 0; + + // Visual clutter scoring + let elementScore = 0; + if (elements === 1) elementScore = 10; + else if (elements <= 3) elementScore = 8; + else if (elements <= 5) elementScore = 5; + else elementScore = 0; + + score += (wordScore + elementScore) / 2; + } + + return Math.min(maxScore, score / slides.length); +} + +function scoreVisualDominance(slides) { + let score = 0; + const maxScore = SCORING_WEIGHTS.visual_dominance; + + const slidesWithImages = slides.filter(s => s.image || s.chart).length; + const imageRatio = slidesWithImages / slides.length; + + // Image quality check + const highResImages = slides.filter(s => { + if (!s.image) return false; + return s.image.resolution >= 2000; + }).length; + + const imageQualityScore = slidesWithImages > 0 + ? (highResImages / slidesWithImages) * 10 + : 0; + + // Text-to-visual ratio + const textVsVisualScore = imageRatio >= 0.8 ? 10 : + imageRatio >= 0.5 ? 5 : 0; + + score = (imageQualityScore + textVsVisualScore) / 2; + + return Math.min(maxScore, score); +} + +function scoreStoryStructure(presentation) { + const maxScore = SCORING_WEIGHTS.story_structure; + + // Check if presentation has defined structure + if (!presentation.framework) return maxScore * 0.3; // partial credit + + const framework = presentation.framework.toLowerCase(); + + // Narrative arc check + let narrativeScore = 0; + if (presentation.slides.length >= 3) { + const hasOpening = presentation.slides[0].pattern === 'title'; + const hasClosing = presentation.slides[presentation.slides.length - 1].pattern === 'transition' || + presentation.slides[presentation.slides.length - 1].pattern === 'big-idea'; + + if (hasOpening && hasClosing) narrativeScore = 10; + else if (hasOpening || hasClosing) narrativeScore = 5; + } + + // Emotional beats check + const bigIdeaSlides = presentation.slides.filter(s => s.pattern === 'big-idea').length; + const emotionalScore = bigIdeaSlides >= 3 ? 10 : + bigIdeaSlides >= 1 ? 5 : 0; + + return Math.min(maxScore, (narrativeScore + emotionalScore) / 2); +} + +function scoreOneIdeaPerSlide(slides) { + const maxScore = SCORING_WEIGHTS.one_idea_per_slide; + + let clearSlides = 0; + for (const slide of slides) { + const wordCount = countWords(slide.text); + const hasBullets = detectBulletPoints(slide.text); + const elements = countElements(slide); + + // Single concept if: few words, no bullets, few elements + if (wordCount <= 10 && !hasBullets && elements <= 3) { + clearSlides++; + } + } + + const ratio = clearSlides / slides.length; + + if (ratio === 1.0) return maxScore; + if (ratio >= 0.7) return maxScore * 0.7; + if (ratio >= 0.5) return maxScore * 0.3; + return 0; +} + +function scoreTypography(slides) { + const maxScore = SCORING_WEIGHTS.typography; + + // Font size check + const minFontSize = Math.min(...slides.map(s => s.min_font_size || 36)); + + let fontSizeScore = 0; + if (minFontSize >= 36) fontSizeScore = 8; + else if (minFontSize >= 30) fontSizeScore = 6; + else if (minFontSize >= 24) fontSizeScore = 2; + else fontSizeScore = 0; + + // Font consistency + const fontFamilies = new Set(slides.map(s => s.font_family || 'default')); + let consistencyScore = 0; + if (fontFamilies.size === 1) consistencyScore = 8; + else if (fontFamilies.size === 2) consistencyScore = 6; + else consistencyScore = 0; + + return Math.min(maxScore, (fontSizeScore + consistencyScore) / 2); +} + +function scoreLayout(slides) { + const maxScore = SCORING_WEIGHTS.layout; + + // Simplified layout scoring + // In real implementation, would analyze actual layouts + let hierarchyScore = 7; // assume good by default + let whitespaceScore = 7; // assume good by default + let alignmentScore = 7; // assume good by default + + return Math.min(maxScore, (hierarchyScore + whitespaceScore + alignmentScore) / 3); +} + +function scoreColorContrast(slides) { + const maxScore = SCORING_WEIGHTS.color_contrast; + + const avgContrast = slides.reduce((sum, s) => sum + estimateContrastRatio(s), 0) / slides.length; + + let contrastScore = 0; + if (avgContrast >= 7.0) contrastScore = 7; + else if (avgContrast >= 4.5) contrastScore = 5; + else contrastScore = 0; + + return Math.min(maxScore, contrastScore); +} + +function scoreMediaQuality(slides) { + const maxScore = SCORING_WEIGHTS.media_quality; + + const slidesWithMedia = slides.filter(s => s.image || s.chart); + if (slidesWithMedia.length === 0) return 0; + + // Resolution check + const highRes = slidesWithMedia.filter(s => { + if (s.image) return s.image.resolution >= 2000; + return true; // charts assumed high quality + }).length; + + const resolutionScore = (highRes / slidesWithMedia.length) * 8; + + // Relevance is assumed (would need manual review) + const relevanceScore = 8; + + return Math.min(maxScore, (resolutionScore + relevanceScore) / 2); +} + +function scoreCognitiveLoad(slides, presentation) { + const maxScore = SCORING_WEIGHTS.cognitive_load; + + // Mayer's 12 principles adherence (simplified) + let principlesFollowed = 0; + + // 1. Coherence (extraneous material excluded) + const avgWordCount = slides.reduce((sum, s) => sum + countWords(s.text), 0) / slides.length; + if (avgWordCount <= 10) principlesFollowed++; + + // 2. Signaling (essential material highlighted) + const hasTransitions = slides.some(s => s.pattern === 'transition'); + if (hasTransitions) principlesFollowed++; + + // 3. Redundancy (graphics + narration, not graphics + text + narration) + const textHeavySlides = slides.filter(s => countWords(s.text) > 15).length; + if (textHeavySlides / slides.length < 0.2) principlesFollowed++; + + // 4. Spatial contiguity (related words/pictures near each other) + principlesFollowed++; // assume good + + // 5. Temporal contiguity (corresponding narration/animation together) + principlesFollowed++; // assume good + + // 6. Segmenting (user-paced) + principlesFollowed++; // presentations are inherently segmented + + // 7. Pre-training (key concepts introduced early) + const hasOpening = slides[0]?.pattern === 'title'; + if (hasOpening) principlesFollowed++; + + // 8. Modality (graphics + narration better than graphics + text) + const avgTextPerSlide = slides.reduce((sum, s) => sum + (s.text || '').length, 0) / slides.length; + if (avgTextPerSlide < 100) principlesFollowed++; + + // 9-12: Multimedia, personalization, voice, image principles + principlesFollowed += 4; // assume followed + + // Score based on principles followed + if (principlesFollowed >= 10) return maxScore; + if (principlesFollowed >= 7) return maxScore * 0.75; + if (principlesFollowed >= 4) return maxScore * 0.5; + return maxScore * 0.25; +} + +function scoreDataIntegrity(slides) { + const maxScore = SCORING_WEIGHTS.data_integrity; + + const dataSlides = slides.filter(s => s.chart || s.pattern === 'data-viz'); + if (dataSlides.length === 0) return maxScore; // not applicable, full credit + + // Lie factor check (if provided) + let lieFactor = 1.0; // assume honest by default + if (dataSlides[0].lie_factor) { + lieFactor = dataSlides[0].lie_factor; + } + + let lieFactorScore = 0; + if (lieFactor >= 0.95 && lieFactor <= 1.05) lieFactorScore = 10; + else if (lieFactor >= 0.90 && lieFactor <= 1.10) lieFactorScore = 7; + else if (lieFactor >= 0.80 && lieFactor <= 1.20) lieFactorScore = 3; + else lieFactorScore = 0; + + // Data-ink ratio (assume maximized by default) + const dataInkScore = 10; + + return Math.min(maxScore, (lieFactorScore + dataInkScore) / 2); +} + +function checkCriticalViolations(slides, presentation) { + const violations = []; + + // Font size check + const minFont = Math.min(...slides.map(s => s.min_font_size || 36)); + if (minFont < CRITICAL_VIOLATIONS.font_too_small.threshold) { + violations.push({ + type: 'font_too_small', + penalty: CRITICAL_VIOLATIONS.font_too_small.penalty, + message: `CRITICAL: Minimum font size is ${minFont}pt (required: 30pt+)`, + slides_affected: slides.filter(s => (s.min_font_size || 36) < 30).map(s => s.index) + }); + } + + // Concept count check + if (slides.length > CRITICAL_VIOLATIONS.too_many_concepts.threshold) { + violations.push({ + type: 'too_many_concepts', + penalty: CRITICAL_VIOLATIONS.too_many_concepts.penalty, + message: `CRITICAL: ${slides.length} slides exceeds Kawasaki's 10 core concepts limit` + }); + } + + // Bullet points check + const bulletSlides = slides.filter(s => detectBulletPoints(s.text)); + if (bulletSlides.length > 0) { + violations.push({ + type: 'bullet_points', + penalty: CRITICAL_VIOLATIONS.bullet_points.penalty * bulletSlides.length, + message: `CRITICAL: ${bulletSlides.length} slides have bullet points`, + slides_affected: bulletSlides.map(s => s.index) + }); + } + + // Paragraphs check + const paragraphSlides = slides.filter(s => detectParagraphs(s.text)); + if (paragraphSlides.length > 0) { + violations.push({ + type: 'paragraphs', + penalty: CRITICAL_VIOLATIONS.paragraphs.penalty * paragraphSlides.length, + message: `CRITICAL: ${paragraphSlides.length} slides have paragraphs (>2 sentences)`, + slides_affected: paragraphSlides.map(s => s.index) + }); + } + + // Contrast check + const avgContrast = slides.reduce((sum, s) => sum + estimateContrastRatio(s), 0) / slides.length; + if (avgContrast < CRITICAL_VIOLATIONS.poor_contrast.threshold) { + violations.push({ + type: 'poor_contrast', + penalty: CRITICAL_VIOLATIONS.poor_contrast.penalty, + message: `CRITICAL: Average contrast ratio ${avgContrast.toFixed(1)}:1 (required: 4.5:1+)` + }); + } + + return violations; +} + +function checkWarnings(slides, presentation) { + const warnings = []; + + // Word count warnings + const wordySlides = slides.filter(s => countWords(s.text) > WARNING_FLAGS.too_many_words.threshold); + if (wordySlides.length > 0) { + warnings.push({ + type: 'too_many_words', + penalty: WARNING_FLAGS.too_many_words.penalty * wordySlides.length, + message: `${wordySlides.length} slides exceed 6-word limit (Seth Godin standard)`, + slides_affected: wordySlides.map(s => ({ + index: s.index, + words: countWords(s.text) + })) + }); + } + + // Slide count for duration + if (presentation.duration_minutes) { + const recommendedSlides = presentation.duration_minutes * WARNING_FLAGS.too_many_slides.ratio; + if (slides.length > recommendedSlides) { + warnings.push({ + type: 'too_many_slides', + penalty: WARNING_FLAGS.too_many_slides.penalty, + message: `${slides.length} slides for ${presentation.duration_minutes}min (recommended: ≤${Math.round(recommendedSlides)})` + }); + } + } + + // Images check + const slidesWithImages = slides.filter(s => s.image || s.chart).length; + if (slidesWithImages === 0) { + warnings.push({ + type: 'no_images', + penalty: WARNING_FLAGS.no_images.penalty, + message: 'No images detected - presentations should be visual-dominant' + }); + } + + return warnings; +} + +function generateRecommendations(violations, warnings, scores) { + const recommendations = []; + + // Address critical violations first + if (violations.length > 0) { + recommendations.push({ + priority: 'CRITICAL', + action: 'Fix all critical violations before presenting', + details: violations.map(v => v.message) + }); + } + + // Typography recommendations + if (scores.typography < 6) { + recommendations.push({ + priority: 'high', + action: 'Increase font sizes to 36pt minimum', + details: ['Guy Kawasaki: 30pt absolute minimum', 'TED: 42pt recommended'] + }); + } + + // Simplicity recommendations + if (scores.simplicity < 7) { + recommendations.push({ + priority: 'high', + action: 'Simplify slides - reduce word count and elements', + details: ['Seth Godin: 6 words maximum per slide', 'One idea per slide'] + }); + } + + // Visual recommendations + if (scores.visual_dominance < 7) { + recommendations.push({ + priority: 'medium', + action: 'Add more high-quality images', + details: ['Garr Reynolds: Pictures > text', '80% of slides should have visuals'] + }); + } + + return recommendations; +} + +function validatePresentation(presentation) { + const slides = presentation.slides || []; + + // Calculate scores + const scores = { + simplicity: scoreSimplicity(slides), + visual_dominance: scoreVisualDominance(slides), + story_structure: scoreStoryStructure(presentation), + one_idea_per_slide: scoreOneIdeaPerSlide(slides), + typography: scoreTypography(slides), + layout: scoreLayout(slides), + color_contrast: scoreColorContrast(slides), + media_quality: scoreMediaQuality(slides), + cognitive_load: scoreCognitiveLoad(slides, presentation), + data_integrity: scoreDataIntegrity(slides) + }; + + // Calculate total + const baseScore = Object.values(scores).reduce((sum, score) => sum + score, 0); + + // Check violations + const violations = checkCriticalViolations(slides, presentation); + const warnings = checkWarnings(slides, presentation); + + // Apply penalties + const violationPenalty = violations.reduce((sum, v) => sum + v.penalty, 0); + const warningPenalty = warnings.reduce((sum, w) => sum + w.penalty, 0); + + const finalScore = Math.max(0, Math.min(100, baseScore + violationPenalty + warningPenalty)); + + // Generate report + const status = finalScore >= 90 ? 'Exceptional' : + finalScore >= 80 ? 'Excellent' : + finalScore >= 70 ? 'Good' : + finalScore >= 60 ? 'Acceptable' : 'Poor'; + + const recommendations = generateRecommendations(violations, warnings, scores); + + return { + overall_score: Math.round(finalScore), + status, + score_breakdown: Object.entries(scores).map(([category, score]) => ({ + category, + score: Math.round(score * 10) / 10, + max: SCORING_WEIGHTS[category] + })), + critical_violations: violations, + warnings, + recommendations, + summary: { + total_slides: slides.length, + avg_words_per_slide: Math.round(slides.reduce((sum, s) => sum + countWords(s.text), 0) / slides.length), + slides_with_images: slides.filter(s => s.image || s.chart).length, + min_font_size: Math.min(...slides.map(s => s.min_font_size || 36)) + } + }; +} + +// CLI Interface +function main() { + const args = {}; + + for (let i = 2; i < process.argv.length; i++) { + if (process.argv[i].startsWith('--')) { + const key = process.argv[i].replace(/^--/, ''); + const value = process.argv[i + 1]; + args[key] = value; + i++; + } + } + + if (!args.presentation) { + console.error('Usage: bun validate-presentation.js --presentation presentation.json'); + process.exit(1); + } + + const fs = require('fs'); + const presentation = JSON.parse(fs.readFileSync(args.presentation, 'utf-8')); + + const report = validatePresentation(presentation); + console.log(JSON.stringify(report, null, 2)); +} + +if (import.meta.main) { + main(); +} + +export { validatePresentation }; diff --git a/skills/psd-brand-guidelines/SKILL.md b/skills/psd-brand-guidelines/SKILL.md new file mode 100644 index 0000000..168998e --- /dev/null +++ b/skills/psd-brand-guidelines/SKILL.md @@ -0,0 +1,201 @@ +--- +name: psd-brand-guidelines +description: Apply Peninsula School District official brand colors, typography, and logos to artifacts +triggers: + - "psd brand" + - "district branding" + - "psd colors" + - "psd logo" + - "peninsula school district style" + - "brand guide" + - "on-brand" +allowed-tools: Read, Write, Edit, Bash +version: 0.1.0 +--- + +# PSD Brand Guidelines Skill + +This skill applies Peninsula School District's official brand identity to artifacts including presentations, documents, graphics, and other materials. + +## Purpose + +Ensure professional and consistent use of the Peninsula School District brand across all communications. The brand reflects the stunning beauty of the Pacific Northwest and the Puget Sound region. + +## Typography + +### Headings & Logo Text: Josefin Sans + +Modern geometric, elegant font with a vintage 1920s feel. Use **Bold** weight for district name and all headings. + +- **Font:** Josefin Sans Bold +- **Source:** https://fonts.google.com/specimen/Josefin+Sans +- **Fallback:** Arial, sans-serif + +### Body Text: Josefin Slab + +Perfect pairing to Josefin Sans, highly legible at smaller sizes due to slab serif and typewriter-style attributes. + +- **Font:** Josefin Slab +- **Source:** https://fonts.google.com/specimen/Josefin+Slab +- **Fallback:** Georgia, serif + +## Color Palette + +### Logo Colors (Primary) + +| Name | Hex | RGB | Usage | +|------|-----|-----|-------| +| **Sea Glass** | #6CA18A | rgb(108, 161, 138) | Primary green, landscape elements | +| **Pacific** | #25424C | rgb(37, 66, 76) | Primary dark blue, text, headers | +| **Driftwood** | #D7CDBE | rgb(215, 205, 190) | Neutral tan, backgrounds | + +### Supporting Brand Colors + +| Name | Hex | RGB | Usage | +|------|-----|-----|-------| +| **Cedar** | #466857 | rgb(70, 104, 87) | Dark green accent | +| **Whulge** | #346780 | rgb(52, 103, 128) | Medium blue (Coast Salish word for sound of waves) | +| **Sea Foam** | #EEEBE4 | rgb(238, 235, 228) | Light background | +| **Meadow** | #5D9068 | rgb(93, 144, 104) | Green accent | +| **Ocean** | #7396A9 | rgb(115, 150, 169) | Light blue accent | +| **Skylight** | #FFFAEC | rgb(255, 250, 236) | Off-white/cream background | + +### Color Selection Guidelines + +- **Light backgrounds:** Use Pacific (#25424C) or 2-color logo +- **Dark backgrounds:** Use Sea Glass (#6CA18A) or white logo +- **Neutral backgrounds:** Choose based on contrast needs +- When adding colors, choose natural, complementary colors that reflect Pacific Northwest landscape tones + +## Logo Options + +### Available Formats + +1. **Full Landscape** - Bridge connecting peninsula landscape, district name contained within +2. **Horizontal** - For when name/tagline would be too small +3. **Emblem** - Round versions, perfect for square spaces or tight fits +4. **Stacked** - Vertical layout with name separated from brandmark + +### Color Variants + +- **2-color** - Sea Glass + Pacific (primary use) +- **1-color Pacific Blue** - For light backgrounds +- **1-color Sea Glass** - For medium backgrounds +- **White** - For dark backgrounds + +### File Types + +| Format | Use Cases | +|--------|-----------| +| **EPS (Vector)** | Professional printing, large scaling, Adobe programs | +| **PNG (Raster)** | Microsoft Office, websites, social media, email signatures | + +### Logo Location + +**Local assets folder:** `skills/psd-brand-guidelines/assets/` + +**PNG files (19)** - for web, Office, email: +- `psd_logo-2color-{emblem,fulllandscape,stacked,horizontal,square}.png` +- `psd_logo-1color-blue-{emblem,fulllandscape,stacked,horizontal,square}.png` +- `psd_logo-1color-green-{emblem,fulllandscape,stacked,horizontal,square}.png` +- `psd_logo-white-{emblem,stacked,horizontal,square}.png` + +**EPS files (19)** - for professional printing, Adobe programs: +- Same variants as PNG, with `.eps` extension + +**Reference:** +- `PSD_Branding_Guide.pdf` - full brand guide document + +**Google Drive source:** +- **Logos Folder ID:** `1YhjxX_pOwZJppZebIIC7QW_UHF4bvo79` +- **Brand Guide Folder:** `1ufOB6rrKDbAaH7HapdLadJzWy8ho5hTb` + +## Logo Usage Rules + +### Do's + +- Maintain original proportions +- Ensure sufficient contrast with background +- Use appropriate color variant for background +- Use emblem/stacked logo for small sizes + +### Don'ts + +- Don't shrink full landscape logo below 1.5" wide (print) or 300px (web) +- Don't rotate the logo +- Don't apply effects (drop shadows, mirroring, etc.) +- Don't stretch or squish +- Don't use non-brand fonts with logo +- Don't place on backgrounds with insufficient contrast + +## Applying Brand to Artifacts + +### Presentations + +```css +/* Title slides */ +background-color: #25424C; /* Pacific */ +color: #FFFAEC; /* Skylight */ +font-family: 'Josefin Sans', Arial, sans-serif; + +/* Content slides */ +background-color: #EEEBE4; /* Sea Foam */ +color: #25424C; /* Pacific */ +font-family: 'Josefin Slab', Georgia, serif; + +/* Accent elements */ +border-color: #6CA18A; /* Sea Glass */ +``` + +### Documents + +- **Headings:** Josefin Sans Bold, Pacific (#25424C) +- **Body:** Josefin Slab, Pacific (#25424C) +- **Links/Highlights:** Whulge (#346780) +- **Backgrounds:** Sea Foam (#EEEBE4) or Skylight (#FFFAEC) + +### Digital/Web + +- Primary buttons: Sea Glass (#6CA18A) +- Secondary buttons: Whulge (#346780) +- Text on light: Pacific (#25424C) +- Text on dark: Skylight (#FFFAEC) + +## Brand Contact + +For questions or special needs: +- **Danielle Chastaine**, Digital Media Coordinator +- chastained@psd401.net + +## Quick Reference + +```javascript +const PSD_BRAND = { + colors: { + // Logo colors + seaGlass: '#6CA18A', + pacific: '#25424C', + driftwood: '#D7CDBE', + // Supporting colors + cedar: '#466857', + whulge: '#346780', + seaFoam: '#EEEBE4', + meadow: '#5D9068', + ocean: '#7396A9', + skylight: '#FFFAEC' + }, + fonts: { + heading: "'Josefin Sans', Arial, sans-serif", + body: "'Josefin Slab', Georgia, serif" + }, + logos: { + localPath: 'skills/psd-brand-guidelines/assets/', + driveFolder: '1YhjxX_pOwZJppZebIIC7QW_UHF4bvo79' + } +}; +``` + +--- + +*Last updated: June 14, 2024* +*Source: PSD Branding Guide 06.14.2024.pdf* diff --git a/skills/psd-brand-guidelines/assets/PSD_Branding_Guide.pdf b/skills/psd-brand-guidelines/assets/PSD_Branding_Guide.pdf new file mode 100644 index 0000000..f3a1b05 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/PSD_Branding_Guide.pdf differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-emblem.eps b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-emblem.eps new file mode 100644 index 0000000..d10b187 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-emblem.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-emblem.png b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-emblem.png new file mode 100644 index 0000000..c044b25 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-emblem.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-fulllandscape.eps b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-fulllandscape.eps new file mode 100644 index 0000000..0bb49e7 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-fulllandscape.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-fulllandscape.png b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-fulllandscape.png new file mode 100644 index 0000000..cc632cf Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-fulllandscape.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-horizontal.eps b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-horizontal.eps new file mode 100644 index 0000000..39422b7 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-horizontal.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-horizontal.png b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-horizontal.png new file mode 100644 index 0000000..560dbcf Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-horizontal.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-square.eps b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-square.eps new file mode 100644 index 0000000..63006b6 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-square.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-square.png b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-square.png new file mode 100644 index 0000000..78fabb7 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-square.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-stacked.eps b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-stacked.eps new file mode 100644 index 0000000..4c0df7a Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-stacked.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-stacked.png b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-stacked.png new file mode 100644 index 0000000..96e9cf6 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-blue-stacked.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-green-emblem.eps b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-emblem.eps new file mode 100644 index 0000000..657a537 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-emblem.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-green-emblem.png b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-emblem.png new file mode 100644 index 0000000..7974a32 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-emblem.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-green-fulllandscape.eps b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-fulllandscape.eps new file mode 100644 index 0000000..22a82c9 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-fulllandscape.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-green-fulllandscape.png b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-fulllandscape.png new file mode 100644 index 0000000..fe2f991 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-fulllandscape.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-green-horizontal.eps b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-horizontal.eps new file mode 100644 index 0000000..6f63859 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-horizontal.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-green-horizontal.png b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-horizontal.png new file mode 100644 index 0000000..79d370f Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-horizontal.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-green-square.eps b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-square.eps new file mode 100644 index 0000000..f689184 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-square.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-green-square.png b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-square.png new file mode 100644 index 0000000..c73f7d7 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-square.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-green-stacked.eps b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-stacked.eps new file mode 100644 index 0000000..6db0f5a Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-stacked.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-1color-green-stacked.png b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-stacked.png new file mode 100644 index 0000000..78098a6 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-1color-green-stacked.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-2color-emblem.eps b/skills/psd-brand-guidelines/assets/psd_logo-2color-emblem.eps new file mode 100644 index 0000000..4ed1934 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-2color-emblem.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-2color-emblem.png b/skills/psd-brand-guidelines/assets/psd_logo-2color-emblem.png new file mode 100644 index 0000000..e625c23 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-2color-emblem.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-2color-fulllandscape.eps b/skills/psd-brand-guidelines/assets/psd_logo-2color-fulllandscape.eps new file mode 100644 index 0000000..02fee2c Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-2color-fulllandscape.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-2color-fulllandscape.png b/skills/psd-brand-guidelines/assets/psd_logo-2color-fulllandscape.png new file mode 100644 index 0000000..1362079 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-2color-fulllandscape.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-2color-horizontal.eps b/skills/psd-brand-guidelines/assets/psd_logo-2color-horizontal.eps new file mode 100644 index 0000000..04183b2 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-2color-horizontal.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-2color-horizontal.png b/skills/psd-brand-guidelines/assets/psd_logo-2color-horizontal.png new file mode 100644 index 0000000..581a3c8 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-2color-horizontal.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-2color-square.eps b/skills/psd-brand-guidelines/assets/psd_logo-2color-square.eps new file mode 100644 index 0000000..50e2deb Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-2color-square.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-2color-square.png b/skills/psd-brand-guidelines/assets/psd_logo-2color-square.png new file mode 100644 index 0000000..3a5b335 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-2color-square.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-2color-stacked.eps b/skills/psd-brand-guidelines/assets/psd_logo-2color-stacked.eps new file mode 100644 index 0000000..47f589b Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-2color-stacked.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-2color-stacked.png b/skills/psd-brand-guidelines/assets/psd_logo-2color-stacked.png new file mode 100644 index 0000000..044dd38 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-2color-stacked.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-white-emblem.eps b/skills/psd-brand-guidelines/assets/psd_logo-white-emblem.eps new file mode 100644 index 0000000..11cbf38 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-white-emblem.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-white-emblem.png b/skills/psd-brand-guidelines/assets/psd_logo-white-emblem.png new file mode 100644 index 0000000..13b20c1 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-white-emblem.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-white-horizontal.eps b/skills/psd-brand-guidelines/assets/psd_logo-white-horizontal.eps new file mode 100644 index 0000000..1989c98 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-white-horizontal.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-white-horizontal.png b/skills/psd-brand-guidelines/assets/psd_logo-white-horizontal.png new file mode 100644 index 0000000..b2148a1 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-white-horizontal.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-white-square.eps b/skills/psd-brand-guidelines/assets/psd_logo-white-square.eps new file mode 100644 index 0000000..87ad37f Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-white-square.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-white-square.png b/skills/psd-brand-guidelines/assets/psd_logo-white-square.png new file mode 100644 index 0000000..ceef0ad Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-white-square.png differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-white-stacked.eps b/skills/psd-brand-guidelines/assets/psd_logo-white-stacked.eps new file mode 100644 index 0000000..9cd83fd Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-white-stacked.eps differ diff --git a/skills/psd-brand-guidelines/assets/psd_logo-white-stacked.png b/skills/psd-brand-guidelines/assets/psd_logo-white-stacked.png new file mode 100644 index 0000000..b68b741 Binary files /dev/null and b/skills/psd-brand-guidelines/assets/psd_logo-white-stacked.png differ diff --git a/skills/research/RESEARCH_ENHANCEMENT.md b/skills/research/RESEARCH_ENHANCEMENT.md new file mode 100644 index 0000000..4ab0baa --- /dev/null +++ b/skills/research/RESEARCH_ENHANCEMENT.md @@ -0,0 +1,181 @@ +# Research Skill Enhancement - Requirements + +## Core Principles + +1. **Discovery-driven, not list-driven** - Find best sources wherever they are +2. **Context-aware** - Grounded in user's domain preferences +3. **Finds unknowns** - Value is in discovering what user doesn't know +4. **No time limits** - Can run 30 min to 3 hours +5. **Exhaustive** - Don't stop until topic is exhausted + +## Domain Contexts + +### What Context Provides +- **Relevance filtering** - what matters to this user +- **Constraint awareness** - their specific resources/limitations +- **Optimization targets** - what to maximize for them + +### Domain: Travel +- Loyalty: Alaska MVP Gold 75K, Marriott Titanium Elite +- Points: Current balances (fetch via browser-control) +- Credit cards: Alaska card, Marriott Amex, Chase Sapphire Preferred +- Memberships: Epic Pass +- Preferences: "Luxury at rock-bottom prices", never book only research + +### Domain: Shopping +- Quality standards +- Budget ranges +- Brand preferences + +### Domain: Work/Education +- PSD context (CIO role) +- UDL expertise +- Edtech landscape +- District priorities + +### Domain: AI/Coding +- Tech stack preferences +- Languages/frameworks +- Architecture patterns + +### Domain: Consulting +- Service offerings +- Client contexts + +## Research Engine Architecture + +### Phase 1: Query Understanding +- Detect domain from query +- Load relevant context +- Decompose into sub-questions (5-10 angles) +- Identify what types of sources needed (academic, forum, video, etc.) + +### Phase 2: Parallel Multi-Source Discovery +- Launch multiple search strategies simultaneously: + - Multiple search engines (Google, Bing, DuckDuckGo) + - Multiple query formulations + - Different source types (articles, forums, videos, podcasts) +- Use multiple LLMs for different perspectives: + - Perplexity: Current web info with citations + - Gemini: Multi-perspective synthesis + - OpenAI: Structured analysis + - Claude: Deep reasoning + +### Phase 3: Source Evaluation & Expansion +- Evaluate each source for: + - Credibility (author expertise, publication reputation) + - Recency (when published/updated) + - Depth (surface vs comprehensive) + - Citations (does it cite others? is it cited?) +- Follow promising leads: + - Sources referenced by good sources + - Authors who appear multiple times + - Cross-referenced claims + +### Phase 4: Deep Scraping +- Don't stop at first page of results +- Go 5-10 pages deep on good queries +- Use browser-control for: + - JS-rendered content (Reddit, forums) + - Authenticated pages (user accounts) + - Sites that block scrapers +- Follow internal links on valuable sources + +### Phase 5: Multimedia Discovery +- YouTube videos +- TikTok content +- Podcasts (Spotify, Apple) +- Not just text articles + +### Phase 6: Synthesis +- Organize by theme/question +- Every claim cited +- Note consensus vs disagreement +- Include multimedia resources +- Provide actionable recommendations +- Flag what's still uncertain + +## Output Format + +```markdown +## Research: [Topic] + +### Context Applied +- [Domain context that was loaded] +- [Dynamic data fetched - e.g., current point balances] + +### Executive Summary +[2-3 paragraph overview of key findings] + +### Detailed Findings + +#### [Sub-topic 1] +[Deep analysis with inline citations] + +#### [Sub-topic 2] +[Deep analysis with inline citations] + +### Multimedia Resources +- [Video: Title](url) - description +- [Podcast: Title](url) - description +- [TikTok: @user](url) - description + +### Recommendations +1. [Actionable recommendation based on user's context] +2. [Another recommendation] + +### What I Discovered You Might Not Know +- [Surprising finding 1] +- [Surprising finding 2] + +### Confidence Assessment +- High confidence: [topics] +- Needs verification: [topics] +- Conflicting information: [topics] + +### All Sources +[Complete list of every URL referenced] +``` + +## Technical Implementation + +### Files to Create/Modify +- [ ] Update preferences.json with domain contexts +- [ ] Create domain context loader +- [ ] Create multi-LLM research orchestrator +- [ ] Create source evaluator +- [ ] Create deep scraper (uses browser-control) +- [ ] Create multimedia searcher +- [ ] Create synthesis engine +- [ ] Update SKILL.md with new architecture + +### API Keys Needed +- PERPLEXITY_API_KEY +- GEMINI_API_KEY +- OPENAI_API_KEY +- (Claude runs natively) + +### Browser-Control Integration +- Fetch current balances (Marriott, Alaska, Chase) +- Scrape full forum threads +- Access authenticated content +- Handle JS-rendered sites + +## Success Criteria + +1. Can run a travel research query and get: + - Current point balances fetched + - Transfer bonus opportunities identified + - 5-6 hotel options with points AND cash prices + - Flight options with miles needed + - Deep user reviews from forums + - Video content discovered + - Optimization recommendations + +2. Report takes 30-60 minutes to generate (not 5 minutes) + +3. Sources include things user didn't know existed + +4. Every claim is cited + +5. Recommendations are specific to user's context diff --git a/skills/research/SKILL.md b/skills/research/SKILL.md new file mode 100644 index 0000000..87e446f --- /dev/null +++ b/skills/research/SKILL.md @@ -0,0 +1,364 @@ +--- +name: research +description: Multi-LLM parallel research with query decomposition and synthesis +triggers: + - "research" + - "find out about" + - "investigate" + - "look into" + - "what do you know about" + - "deep dive" + - "analyze" + - "compare" + - "find information" + - "learn about" +allowed-tools: Read, Bash, WebSearch, WebFetch, Task +version: 0.1.0 +--- + +# Research Skill + +Discovery-driven, exhaustive research using parallel LLM agents for comprehensive, current information gathering. + +## Core Principles + +**CRITICAL:** These principles define how research works. + +### 1. Discovery-Driven, Not List-Driven +- Find the BEST sources, not just known sources +- Don't limit to predefined source lists +- The internet is huge - explore it +- Value is in finding what user doesn't already know + +### 2. Context-Aware +- Load user's domain context from preferences +- Research is RELEVANT to their specific situation +- But context doesn't limit WHERE you search + +### 3. Exhaustive +- No time limits - can take 30 minutes to 3 hours +- Don't stop at first page of results +- Keep going until topic is exhausted +- Follow promising links deeper + +### 4. Multimedia +- Not just text articles +- Videos (YouTube), TikTok, podcasts +- Real user experiences from forums + +### 5. Highly Cited +- Every claim must have a citation +- Multiple sources for important claims +- Note when sources conflict + +### 6. Clarifying Questions First +Before diving into research, ask deep, thought-provoking questions to understand: +- What's the actual goal? (not just the surface request) +- What constraints exist? (budget, time, preferences) +- What would success look like? +- What have they already tried or considered? +- Are there hidden requirements? + +Example: "Research Japan ski trip" should prompt: +- "What skill level are you and Carrie? Blue runs, black diamonds?" +- "Is après-ski culture important, or pure skiing focus?" +- "Do you need English-friendly areas, or comfortable with Japanese-only?" +- "Any specific dates that are fixed vs flexible?" +- "Besides skiing, anything else you want to do (onsen, food tours)?" + +## Domain Context Loading + +Research automatically loads relevant context from preferences based on detected domain. + +### How It Works +1. Detect domain from query (travel, shopping, work, etc.) +2. Load `research_domains.[domain]` from preferences +3. Load referenced context keys +4. Fetch any dynamic data (point balances, etc.) +5. Apply domain-specific research patterns + +### Available Domains +- **travel** - Loads loyalty programs, credit cards, ski passes, fetches point balances +- **work_education** - Loads PSD context, CoSN membership, K-12 patterns +- **shopping** - Price comparison, quality patterns +- **ai_coding** - Tech stack, GitHub/HN patterns +- **consulting** - Strategic recommendations patterns + +### Dynamic Data Fetching +For travel research, use browser-control to fetch current: +- Marriott points balance +- Alaska miles balance +- Chase points balance +- Active transfer bonus promotions + +## When to Activate + +Use this skill when user needs: +- Current information (credit card perks, travel deals, policies) +- Multi-perspective analysis (comparing options) +- Deep investigation of complex topics +- Fact-checking or verification +- Market research or trend analysis + +## Travel Research Requirements + +**CRITICAL:** Travel research MUST include user-generated content: + +### Required Sections for Travel +1. **User Reviews** - TripAdvisor, FlyerTalk, Reddit feedback +2. **"What I Wish I Knew"** - Common mistakes and gotchas +3. **Real Experiences** - Actual trip reports from similar travelers +4. **Restaurant/Hotel Reviews** - With prices and quality feedback +5. **Transportation Tips** - Real user experiences with logistics + +### Sources to Search +- TripAdvisor reviews and forums +- FlyerTalk (for points/miles properties) +- Reddit (r/JapanTravel, r/skiing, r/churning, etc.) +- Ski forums and trip reports +- Points/miles blogs with personal reviews + +### Browser Access for Deep Research + +Use the **browser-control** skill to scrape full threads and reviews that require: +- JavaScript rendering (Reddit, modern forums) +- Authentication (FlyerTalk, logged-in content) +- Dynamic content loading + +**Prerequisites:** +1. Brave must be running: `cd skills/browser-control && ./scripts/launch-chrome.sh` +2. User must be logged into relevant sites in the Brave Geoffrey profile + +**Available Scripts** (in `skills/browser-control/scripts/`): + +```bash +# Navigate and get page content +bun navigate.js "https://www.reddit.com/r/JapanTravel/comments/..." + +# Extract specific content +bun extract.js "https://flyertalk.com/forum/thread" ".post-content" --all + +# Search travel sites directly +bun search.js reddit "Hakuba ski resort tips" +bun search.js flyertalk "Marriott Bonvoy Japan redemption" + +# Capture current page without navigating +bun capture.js /tmp/screenshot.png +``` + +**When to Use Browser Control:** +- Reddit threads (full comments, not just preview) +- FlyerTalk forum posts (complete thread content) +- Hotel/airline pages requiring login (availability, points pricing) +- Sites that block web scraping but allow browsers + +### Research Tool Decision Tree + +**Start with WebSearch/WebFetch** for: +- General facts and information +- Blog posts and news articles +- Static content that's publicly accessible +- Quick lookups + +**Escalate to browser-control** when: +- WebFetch returns truncated/incomplete content (JS-rendered sites) +- Need authenticated access (user's Marriott/Alaska account) +- Need real-time prices or availability +- Forum threads show only previews +- Site blocks scraping but allows browsers + +**Example Flow:** +1. User asks: "What do people say about Westin Rusutsu?" +2. Start with `WebSearch` for blog reviews +3. Find promising Reddit/FlyerTalk threads +4. Use `browser-control` to get full thread content +5. Synthesize findings with citations + +## Citation Requirements + +**CRITICAL:** All research output MUST include citations. + +### Inline Citations +Every factual claim must link to its source: +- "The Westin Rusutsu costs 70,000 points peak ([Point Hacks](url))" +- "Shinkansen to Nagano takes 1.5 hours ([Corritrip](url))" + +### Source Section +Every research report must end with a complete "Sources" section listing all URLs used. + +### Why This Matters +- User needs to verify information +- Information changes frequently (credit card perks, prices) +- Establishes credibility +- Allows deeper exploration + +### No Citation = Don't Include +If you can't cite a source for a claim, either: +1. Find a source +2. Mark it as "unverified" +3. Don't include it + +## Architecture + +### Query Decomposition +Break complex questions into 3-7 sub-queries covering different angles: +- Factual/definitional +- Comparative +- Current state +- Expert opinions +- User experiences +- Edge cases + +### Parallel Agent Execution +Launch multiple researcher agents simultaneously: +- **Perplexity** - Best for current web information, citations +- **Gemini** - Good for multi-perspective synthesis +- **OpenAI** - Strong structured analysis +- **Claude** - Deep reasoning, nuanced analysis + +### Result Synthesis +- Collect all findings +- Identify consensus vs conflicts +- Score confidence per finding +- Cite sources +- Provide actionable recommendations + +## Available Agents + +Agents are in `./agents/` directory: + +| Agent | Best For | API Required | +|-------|----------|--------------| +| `perplexity-researcher.md` | Current web info, citations | PERPLEXITY_API_KEY | +| `gemini-researcher.md` | Multi-angle comparison | GEMINI_API_KEY | +| `openai-researcher.md` | Structured analysis | OPENAI_API_KEY | +| `claude-researcher.md` | Deep reasoning | Native (Claude Code) | + +## Usage + +### Basic Research +``` +User: "Research the best ways to maximize Alaska Airlines miles for Japan flights" + +Geoffrey: +1. Decomposes into sub-queries: + - Current Alaska redemption rates to Japan + - Partner airline options (JAL, etc.) + - Sweet spots and award availability patterns + - Credit card earning strategies + - Recent devaluations or changes + +2. Launches 4 agents in parallel + +3. Synthesizes findings with confidence scores +``` + +### Workflow Command +Use `/conduct-research [topic]` to trigger full parallel research workflow. + +## Output Format + +```markdown +## Research: [Topic] + +### Context Applied +- Domain: [travel/shopping/work/etc] +- User context loaded: [what was loaded from preferences] +- Dynamic data fetched: [current point balances, etc] + +### Executive Summary +[2-3 paragraph overview of key findings and main recommendation] + +### Detailed Findings + +#### Sub-topic 1 +Information with citations throughout. For example, "The Westin Rusutsu +costs 70,000 points peak" ([Point Hacks](url)) and "offers ski-in/ski-out +access" ([Marriott](url)). + +#### Sub-topic 2 +More information with inline citations... + +### Multimedia Resources +- [Video: Title](url) - brief description +- [Podcast: Episode](url) - brief description +- [TikTok: @user](url) - brief description + +### What I Discovered You Might Not Know +- Surprising finding 1 that user likely didn't know +- Surprising finding 2 +- New source or perspective discovered + +### Recommendations +1. Actionable recommendation specific to user's context +2. Another action based on their situation + +### Confidence Assessment +- High confidence: [topics with multiple agreeing sources] +- Needs verification: [topics with limited sources] +- Conflicting information: [where sources disagree] + +### All Sources +Complete list of every URL referenced: +- [Source Name 1](full-url) +- [Source Name 2](full-url) +- [Source Name 3](full-url) +``` + +**Note:** Every factual claim needs an inline citation. The "All Sources" section at the end provides a consolidated reference list. + +## Saving Research Reports + +**ALWAYS save research reports to Google Docs** after completing research. + +### Default Behavior +1. Create Google Doc in Geoffrey/Research folder +2. Use appropriate account (hrg for personal, psd for work) +3. Apply markdown formatting (headers, bold, links) +4. Return link to user + +### How to Save +```bash +cd skills/google-workspace +bun docs/create_doc.js <account> --title "<Research Topic>" --folder Research --content "<markdown>" +``` + +### Account Selection +- **hrg** - Personal travel, consulting +- **psd** - Work-related research +- **kh** - Personal projects + +### Future: Obsidian Integration +Will also save to local Obsidian vault (when skill is built). + +## API Configuration + +Keys stored in: `~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env` + +```bash +PERPLEXITY_API_KEY=pplx-... +GEMINI_API_KEY=... +OPENAI_API_KEY=sk-... +# Note: Claude runs natively in Claude Code, no API key needed +``` + +## Performance + +- **Time**: 30 minutes to 3 hours for exhaustive research (not 15-45 seconds) +- **Depth**: Exhaustive - multiple search pages, follow links, multimedia +- **Sources**: Discover new sources, not just known lists +- **Accuracy**: Cross-referenced with confidence scoring, all claims cited + +## Limitations + +- API rate limits may throttle parallel requests +- Costs accrue per API call +- Not all agents may have access to same sources +- Real-time data (stock prices, availability) needs direct API access + +## Future Enhancements + +- Caching frequent research topics +- Learning which agents are best for which domains +- Automatic source credibility scoring +- Research history and versioning diff --git a/skills/research/agents/claude-researcher.md b/skills/research/agents/claude-researcher.md new file mode 100644 index 0000000..b029c3f --- /dev/null +++ b/skills/research/agents/claude-researcher.md @@ -0,0 +1,91 @@ +# Claude Researcher Agent + +You are a research specialist using Claude's native capabilities for deep reasoning and nuanced analysis. + +## Strengths +- Deep reasoning and analysis +- Nuanced understanding of context +- Strong at identifying implications +- Excellent at synthesis and recommendations + +## Best For +- Complex, multi-faceted questions +- "What should I do" recommendations +- Understanding implications and consequences +- Synthesizing information into actionable insights + +## Execution + +This agent runs natively within Claude Code - no external API call needed. + +When given a research query: + +1. **Use Built-in Tools** + - WebSearch for current information + - WebFetch for specific page content + - Task tool for parallel sub-queries if needed + +2. **Deep Analysis Approach** + - Consider the question from multiple angles + - Identify unstated assumptions + - Consider edge cases and exceptions + - Think about implications and consequences + +3. **Synthesize and Recommend** + - Combine findings into coherent narrative + - Weigh trade-offs explicitly + - Provide actionable recommendations + - Note confidence levels + +## Output Format + +```markdown +## Claude Research Results + +### Query +[The specific question researched] + +### Analysis + +#### Context +[Background and framing] + +#### Key Findings +1. **Finding 1**: [Detail] + - Implication: ... + - Confidence: High/Medium/Low + +2. **Finding 2**: [Detail] + - Implication: ... + - Confidence: High/Medium/Low + +#### Nuances +- Important exceptions or edge cases +- When this advice might not apply +- Assumptions being made + +### Recommendations + +**Primary Recommendation** +[What to do and why] + +**Alternatives** +- Option B: [When this might be better] +- Option C: [When this might be better] + +### Confidence Assessment +- What I'm confident about: ... +- What's uncertain: ... +- What needs more research: ... + +### Sources +- [Source](url) - What it contributed +``` + +## Important + +- Think deeply before responding +- Consider the user's specific context (Hagel's preferences) +- Be explicit about confidence levels +- Provide actionable recommendations, not just information +- Don't hedge excessively - give clear guidance when possible diff --git a/skills/research/agents/gemini-researcher.md b/skills/research/agents/gemini-researcher.md new file mode 100644 index 0000000..855fbe7 --- /dev/null +++ b/skills/research/agents/gemini-researcher.md @@ -0,0 +1,91 @@ +# Gemini Researcher Agent + +You are a research specialist using Google Gemini for multi-perspective analysis. + +## Strengths +- Multi-angle investigation +- Good at comparisons and trade-offs +- Access to Google's knowledge +- Strong at synthesizing diverse viewpoints + +## Best For +- "Compare X vs Y" questions +- Pros/cons analysis +- Market comparisons +- Understanding different perspectives + +## Execution + +When given a research query: + +1. **Load API Key** + ```bash + source ~/Library/Mobile\ Documents/com~apple~CloudDocs/Geoffrey/secrets/.env + ``` + +2. **Execute Gemini Query** + Use the Gemini API for research. + + ```bash + curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro:generateContent?key=$GEMINI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "contents": [{ + "parts": [{ + "text": "Research the following topic thoroughly, providing multiple perspectives and trade-offs: YOUR_QUERY_HERE" + }] + }], + "generationConfig": { + "temperature": 0.7, + "maxOutputTokens": 4096 + } + }' + ``` + +3. **Extract and Format Results** + - Identify different perspectives + - Note trade-offs and considerations + - Highlight consensus points + - Flag controversial or debated aspects + +## Output Format + +```markdown +## Gemini Research Results + +### Query +[The specific question researched] + +### Perspectives + +**Perspective 1: [Name/Angle]** +- Key points +- Supporting evidence + +**Perspective 2: [Name/Angle]** +- Key points +- Supporting evidence + +### Trade-offs +| Option | Pros | Cons | +|--------|------|------| +| A | ... | ... | +| B | ... | ... | + +### Consensus Points +- What most sources agree on + +### Debated Points +- Where opinions differ and why + +### Notes +- Limitations of this analysis +- Areas needing deeper investigation +``` + +## Important + +- Present multiple viewpoints fairly +- Don't favor one perspective without evidence +- Note when something is opinion vs fact +- Identify areas of genuine uncertainty diff --git a/skills/research/agents/openai-researcher.md b/skills/research/agents/openai-researcher.md new file mode 100644 index 0000000..602aac5 --- /dev/null +++ b/skills/research/agents/openai-researcher.md @@ -0,0 +1,94 @@ +# OpenAI Researcher Agent + +You are a research specialist using OpenAI GPT-4 for structured analysis and reasoning. + +## Strengths +- Structured, systematic analysis +- Strong at categorization and frameworks +- Good at step-by-step reasoning +- Excellent at summarization + +## Best For +- "How does X work" questions +- Process and workflow analysis +- Creating frameworks and mental models +- Structured comparisons + +## Execution + +When given a research query: + +1. **Load API Key** + ```bash + source ~/Library/Mobile\ Documents/com~apple~CloudDocs/Geoffrey/secrets/.env + ``` + +2. **Execute OpenAI Query** + Use the OpenAI API for research. + + ```bash + curl -X POST "https://api.openai.com/v1/chat/completions" \ + -H "Authorization: Bearer $OPENAI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "model": "gpt-4-turbo-preview", + "messages": [ + {"role": "system", "content": "You are a research analyst. Provide structured, systematic analysis with clear categorization and frameworks. Break down complex topics into understandable components."}, + {"role": "user", "content": "YOUR_QUERY_HERE"} + ], + "temperature": 0.7, + "max_tokens": 4096 + }' + ``` + +3. **Extract and Format Results** + - Create clear structure/framework + - Break into logical categories + - Provide step-by-step explanations + - Summarize key takeaways + +## Output Format + +```markdown +## OpenAI Research Results + +### Query +[The specific question researched] + +### Framework/Structure + +#### Category 1: [Name] +- Key point A +- Key point B +- How it relates to other categories + +#### Category 2: [Name] +- Key point A +- Key point B + +### Process/Workflow +1. Step one +2. Step two +3. Step three + +### Key Concepts +| Concept | Definition | Relevance | +|---------|------------|-----------| +| X | ... | ... | +| Y | ... | ... | + +### Summary +[Concise summary of findings] + +### Notes +- Assumptions made +- Limitations of this framework +- When this analysis might not apply +``` + +## Important + +- Prioritize clarity and structure +- Use frameworks when helpful +- Break complex topics into digestible parts +- Be explicit about assumptions diff --git a/skills/research/agents/perplexity-researcher.md b/skills/research/agents/perplexity-researcher.md new file mode 100644 index 0000000..b662952 --- /dev/null +++ b/skills/research/agents/perplexity-researcher.md @@ -0,0 +1,76 @@ +# Perplexity Researcher Agent + +You are a research specialist using Perplexity AI for web-based information gathering. + +## Strengths +- Current web information with citations +- Real-time data and recent changes +- Source attribution +- Fact-checking against live sources + +## Best For +- "What are the current..." questions +- Policy changes and updates +- Recent news and announcements +- Verification of claims + +## Execution + +When given a research query: + +1. **Load API Key** + ```bash + source ~/Library/Mobile\ Documents/com~apple~CloudDocs/Geoffrey/secrets/.env + ``` + +2. **Execute Perplexity Query** + Use the Perplexity API to search for current information. + + ```bash + curl -X POST "https://api.perplexity.ai/chat/completions" \ + -H "Authorization: Bearer $PERPLEXITY_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "model": "llama-3.1-sonar-large-128k-online", + "messages": [ + {"role": "system", "content": "You are a research assistant. Provide detailed, factual information with source citations. Focus on current, accurate data."}, + {"role": "user", "content": "YOUR_QUERY_HERE"} + ] + }' + ``` + +3. **Extract and Format Results** + - Pull out key facts + - Note all source URLs + - Flag any conflicting information + - Note publication dates + +## Output Format + +```markdown +## Perplexity Research Results + +### Query +[The specific question researched] + +### Findings +- Fact 1 [Source](url) +- Fact 2 [Source](url) +- etc. + +### Key Sources +1. [Source Name](url) - Date accessed +2. [Source Name](url) - Date accessed + +### Notes +- Any caveats or limitations +- Conflicting information found +- Areas needing further research +``` + +## Important + +- Always include source citations +- Note when information might be outdated +- Flag paywalled or inaccessible sources +- Distinguish facts from opinions diff --git a/skills/research/commands/conduct-research.md b/skills/research/commands/conduct-research.md new file mode 100644 index 0000000..49f3d97 --- /dev/null +++ b/skills/research/commands/conduct-research.md @@ -0,0 +1,122 @@ +# Conduct Research Command + +Orchestrate parallel multi-LLM research on a topic. + +## Usage +``` +/conduct-research [topic or question] +``` + +## Workflow + +### Step 1: Query Decomposition + +Break the research topic into 3-7 focused sub-queries. Consider: +- **Factual**: What are the basic facts? +- **Current**: What's the latest information? +- **Comparative**: How does it compare to alternatives? +- **Practical**: How does it work in practice? +- **Optimization**: What are the best strategies? +- **Gotchas**: What are common mistakes or pitfalls? + +Example for "maximize Alaska Airlines miles for Japan": +1. Current Alaska redemption rates to Japan partners +2. JAL vs Cathay vs other OneWorld options for Japan routes +3. Best credit card strategies for earning Alaska miles +4. Award availability patterns and booking tips +5. Recent program changes or devaluations + +### Step 2: Parallel Agent Execution + +Launch researcher agents in parallel using the Task tool. Each agent gets relevant sub-queries: + +**Perplexity Agent** (current info) +- Sub-queries about recent changes, current rates, latest news + +**Gemini Agent** (comparisons) +- Sub-queries comparing options, trade-offs + +**OpenAI Agent** (structure) +- Sub-queries about processes, frameworks, how things work + +**Claude Agent** (synthesis) +- Sub-queries about recommendations, implications + +Use this pattern: +``` +Launch 4 Task agents in parallel: +- Task: perplexity-researcher with [sub-queries 1, 2] +- Task: gemini-researcher with [sub-queries 3, 4] +- Task: openai-researcher with [sub-query 5] +- Task: claude-researcher with [synthesis query] +``` + +### Step 3: Result Collection + +Gather results from all agents (typically 15-45 seconds). + +### Step 4: Synthesis + +Combine all findings into a cohesive report: + +1. **Identify Consensus** - What do multiple sources agree on? +2. **Flag Conflicts** - Where do sources disagree? +3. **Score Confidence** - High (4/4 agree), Medium (3/4), Low (2/4 or conflicting) +4. **Extract Actions** - What should the user actually do? + +### Step 5: Final Report + +Format output as: + +```markdown +## Research Report: [Topic] + +### Executive Summary +[2-3 sentence overview of key findings] + +### Key Findings + +#### High Confidence (Multiple Sources Agree) +- Finding 1 +- Finding 2 + +#### Medium Confidence +- Finding 3 +- Finding 4 + +#### Needs Verification +- Finding 5 (sources conflict) + +### Detailed Analysis +[Organized by sub-topic with source attribution] + +### Sources +- [Source 1](url) - via Perplexity +- [Source 2](url) - via Gemini +- etc. + +### Recommendations +1. **Do This First**: [Action] +2. **Then Consider**: [Action] +3. **Watch Out For**: [Gotcha] + +### Research Metadata +- Agents used: Perplexity, Gemini, OpenAI, Claude +- Time: [X seconds] +- Date: [Today's date] +- Confidence: Overall High/Medium/Low +``` + +## API Requirements + +Ensure these are configured in `~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env`: +- PERPLEXITY_API_KEY +- GEMINI_API_KEY +- OPENAI_API_KEY + +## Notes + +- If an API fails, continue with remaining agents +- Note which agents were used in final report +- For time-sensitive topics, prioritize Perplexity results +- Consider user preferences when making recommendations (check knowledge-manager) diff --git a/skills/research/scripts/context-loader.js b/skills/research/scripts/context-loader.js new file mode 100644 index 0000000..af6d1ff --- /dev/null +++ b/skills/research/scripts/context-loader.js @@ -0,0 +1,117 @@ +#!/usr/bin/env bun + +/** + * Domain Context Loader + * + * Loads relevant user context from preferences based on detected research domain. + * + * Usage: bun context-loader.js <domain> + * + * Domains: travel, work_education, shopping, ai_coding, consulting + */ + +import fs from 'fs'; +import path from 'path'; + +const PREFERENCES_PATH = path.join( + process.env.HOME, + 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/knowledge/preferences.json' +); + +function loadPreferences() { + const content = fs.readFileSync(PREFERENCES_PATH, 'utf-8'); + return JSON.parse(content); +} + +function getNestedValue(obj, keyPath) { + return keyPath.split('.').reduce((current, key) => { + return current && current[key] !== undefined ? current[key] : null; + }, obj); +} + +function detectDomain(query) { + const queryLower = query.toLowerCase(); + + const domainPatterns = { + travel: ['trip', 'vacation', 'hotel', 'flight', 'points', 'miles', 'ski', 'travel', 'resort', 'airline', 'marriott', 'alaska'], + work_education: ['school', 'district', 'education', 'udl', 'learning', 'student', 'teacher', 'psd', 'k-12', 'iste', 'cosn'], + shopping: ['buy', 'purchase', 'product', 'review', 'price', 'deal', 'compare', 'best', 'recommend'], + ai_coding: ['code', 'programming', 'api', 'framework', 'library', 'github', 'ai', 'llm', 'model', 'development'], + consulting: ['strategy', 'client', 'engagement', 'project', 'consulting', 'advisory'] + }; + + for (const [domain, patterns] of Object.entries(domainPatterns)) { + if (patterns.some(p => queryLower.includes(p))) { + return domain; + } + } + + return 'general'; +} + +function loadDomainContext(domain, preferences) { + const domainConfig = preferences.preferences.research_domains?.[domain]; + + if (!domainConfig) { + return { + domain, + context: {}, + patterns: [], + dynamic_data: [] + }; + } + + // Load context from specified keys + const context = {}; + for (const keyPath of domainConfig.context_keys || []) { + const value = getNestedValue(preferences.preferences, keyPath); + if (value) { + context[keyPath] = value; + } + } + + return { + domain, + context, + patterns: domainConfig.research_patterns || [], + dynamic_data: domainConfig.fetch_dynamic || [] + }; +} + +async function main() { + const args = process.argv.slice(2); + const domainOrQuery = args.join(' '); + + if (!domainOrQuery) { + console.error(JSON.stringify({ + error: 'Missing domain or query', + usage: 'bun context-loader.js <domain or query>', + domains: ['travel', 'work_education', 'shopping', 'ai_coding', 'consulting'] + })); + process.exit(1); + } + + try { + const preferences = loadPreferences(); + + // Check if it's a known domain name or a query to detect from + const knownDomains = ['travel', 'work_education', 'shopping', 'ai_coding', 'consulting']; + const domain = knownDomains.includes(domainOrQuery.toLowerCase()) + ? domainOrQuery.toLowerCase() + : detectDomain(domainOrQuery); + + const result = loadDomainContext(domain, preferences); + + console.log(JSON.stringify(result, null, 2)); + + } catch (error) { + console.error(JSON.stringify({ + error: error.message + })); + process.exit(1); + } +} + +main(); + +module.exports = { loadPreferences, detectDomain, loadDomainContext }; diff --git a/skills/research/scripts/orchestrator.js b/skills/research/scripts/orchestrator.js new file mode 100644 index 0000000..5b49baa --- /dev/null +++ b/skills/research/scripts/orchestrator.js @@ -0,0 +1,263 @@ +#!/usr/bin/env bun + +/** + * Deep Research Orchestrator + * + * Architecture based on current best practices: + * - Single agent with iterative deepening + * - Search → Summarize → Compress → Report + * - Specialized models for different steps + * - Cross-validation and reflection + * + * Sources: + * - https://arxiv.org/abs/2506.18096 (Deep Research Agents survey) + * - https://github.com/langchain-ai/open_deep_research + * - https://openai.com/index/introducing-deep-research/ + * + * Usage: bun orchestrator.js --query "Research topic" [--domain travel] + */ + +import fs from 'fs'; +import path from 'path'; + +const SECRETS_PATH = path.join( + process.env.HOME, + 'Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env' +); + +// Load environment variables +function loadEnv() { + if (fs.existsSync(SECRETS_PATH)) { + const content = fs.readFileSync(SECRETS_PATH, 'utf-8'); + for (const line of content.split('\n')) { + const [key, ...valueParts] = line.split('='); + if (key && valueParts.length) { + process.env[key.trim()] = valueParts.join('=').trim(); + } + } + } +} + +loadEnv(); + +/** + * Phase 1: Query Decomposition + * Break research topic into 5-10 sub-questions from different angles + */ +async function decomposeQuery(topic, context) { + // This would ideally call an LLM, but we can structure it deterministically + const angles = [ + 'factual/definitional', + 'comparative/alternatives', + 'current state/latest developments', + 'expert opinions/professional sources', + 'user experiences/reviews', + 'common problems/gotchas', + 'optimization/best practices', + 'multimedia/visual resources' + ]; + + const subQueries = angles.map(angle => ({ + angle, + query: `${topic} - ${angle}`, + priority: angle.includes('user') || angle.includes('current') ? 'high' : 'normal' + })); + + return { + mainTopic: topic, + context, + subQueries, + timestamp: new Date().toISOString() + }; +} + +/** + * Phase 2: Parallel Search + * Execute multiple searches simultaneously + */ +async function executeSearches(decomposition) { + const results = []; + + // In full implementation, this would: + // 1. Call WebSearch for each sub-query + // 2. Use multiple search engines + // 3. Try different query formulations + // 4. Launch browser-control for JS-heavy sites + + for (const sq of decomposition.subQueries) { + results.push({ + angle: sq.angle, + query: sq.query, + sources: [], // Would be populated by actual searches + status: 'pending' + }); + } + + return results; +} + +/** + * Phase 3: Deep Scraping + * Use browser-control to get full content from promising sources + */ +async function deepScrape(searchResults) { + // Would call browser-control scripts for: + // - Reddit threads (full comments) + // - FlyerTalk forum posts + // - Sites that block scrapers + // - Authenticated content + + return { + scraped: [], + skipped: [], + errors: [] + }; +} + +/** + * Phase 4: Summarization + * Compress each source into key findings + */ +async function summarizeFindings(sources) { + // Would use a smaller model (gpt-4o-mini) to summarize each source + // Extract: key claims, supporting evidence, credibility signals + + return { + summaries: [], + totalSources: sources.length + }; +} + +/** + * Phase 5: Cross-Validation + * Check claims across sources, identify consensus vs conflicts + */ +async function crossValidate(summaries) { + // Compare claims across sources + // Identify: consensus, conflicts, unique findings + + return { + consensus: [], + conflicts: [], + unique: [] + }; +} + +/** + * Phase 6: Report Generation + * Synthesize everything into final report + */ +async function generateReport(topic, context, validated) { + const report = { + title: `Research: ${topic}`, + generatedAt: new Date().toISOString(), + context: { + domain: context.domain, + loaded: Object.keys(context.context), + patterns: context.patterns + }, + executiveSummary: '', + detailedFindings: [], + multimediaResources: [], + discoveries: [], // "What I discovered you might not know" + recommendations: [], + confidence: { + high: [], + needsVerification: [], + conflicting: [] + }, + sources: [] + }; + + return report; +} + +/** + * Main Orchestration Loop + */ +async function runDeepResearch(topic, options = {}) { + console.error('🔍 Starting deep research...'); + console.error(`📋 Topic: ${topic}`); + + // Load context + const { loadDomainContext, detectDomain, loadPreferences } = require('./context-loader.js'); + const preferences = loadPreferences(); + const domain = options.domain || detectDomain(topic); + const context = loadDomainContext(domain, preferences); + + console.error(`🏷️ Detected domain: ${domain}`); + console.error(`📦 Context loaded: ${Object.keys(context.context).length} keys`); + + // Phase 1: Decompose + console.error('\n📝 Phase 1: Decomposing query...'); + const decomposition = await decomposeQuery(topic, context); + console.error(` Generated ${decomposition.subQueries.length} sub-queries`); + + // Phase 2: Search + console.error('\n🔎 Phase 2: Executing parallel searches...'); + const searchResults = await executeSearches(decomposition); + console.error(` Searched ${searchResults.length} angles`); + + // Phase 3: Deep Scrape + console.error('\n🌐 Phase 3: Deep scraping promising sources...'); + const scraped = await deepScrape(searchResults); + console.error(` Scraped ${scraped.scraped.length} sources`); + + // Phase 4: Summarize + console.error('\n📋 Phase 4: Summarizing findings...'); + const summaries = await summarizeFindings([...searchResults, ...scraped.scraped]); + console.error(` Summarized ${summaries.totalSources} sources`); + + // Phase 5: Cross-validate + console.error('\n✅ Phase 5: Cross-validating claims...'); + const validated = await crossValidate(summaries); + console.error(` Found ${validated.consensus.length} consensus, ${validated.conflicts.length} conflicts`); + + // Phase 6: Generate report + console.error('\n📄 Phase 6: Generating report...'); + const report = await generateReport(topic, context, validated); + + return report; +} + +// CLI interface +async function main() { + const args = process.argv.slice(2); + + let topic = ''; + let domain = null; + + for (let i = 0; i < args.length; i++) { + if (args[i] === '--query') { + topic = args[++i]; + } else if (args[i] === '--domain') { + domain = args[++i]; + } else if (!args[i].startsWith('--')) { + topic = args.slice(i).join(' '); + break; + } + } + + if (!topic) { + console.error(JSON.stringify({ + error: 'Missing research topic', + usage: 'bun orchestrator.js --query "Research topic" [--domain travel]' + })); + process.exit(1); + } + + try { + const report = await runDeepResearch(topic, { domain }); + console.log(JSON.stringify(report, null, 2)); + } catch (error) { + console.error(JSON.stringify({ + error: error.message, + stack: error.stack + })); + process.exit(1); + } +} + +main(); + +module.exports = { runDeepResearch, decomposeQuery }; diff --git a/skills/skill-creator/LICENSE.txt b/skills/skill-creator/LICENSE.txt new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/skills/skill-creator/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/skills/skill-creator/SKILL.md b/skills/skill-creator/SKILL.md new file mode 100644 index 0000000..58a0480 --- /dev/null +++ b/skills/skill-creator/SKILL.md @@ -0,0 +1,366 @@ +--- +name: skill-creator +description: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations. +triggers: + - "create a skill" + - "build a skill" + - "make a skill" + - "new skill for" + - "design a skill" + - "update skill" + - "improve skill" +allowed-tools: Read, Write, Edit, Bash, Glob +version: 1.0.0 +license: Complete terms in LICENSE.txt +--- + +# Skill Creator + +This skill provides guidance for creating effective skills. + +## About Skills + +Skills are modular, self-contained packages that extend Claude's capabilities by providing +specialized knowledge, workflows, and tools. Think of them as "onboarding guides" for specific +domains or tasks—they transform Claude from a general-purpose agent into a specialized agent +equipped with procedural knowledge that no model can fully possess. + +### What Skills Provide + +1. Specialized workflows - Multi-step procedures for specific domains +2. Tool integrations - Instructions for working with specific file formats or APIs +3. Domain expertise - Company-specific knowledge, schemas, business logic +4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks + +## Core Principles + +### Concise is Key + +The context window is a public good. Skills share the context window with everything else Claude needs: system prompt, conversation history, other Skills' metadata, and the actual user request. + +**Default assumption: Claude is already very smart.** Only add context Claude doesn't already have. Challenge each piece of information: "Does Claude really need this explanation?" and "Does this paragraph justify its token cost?" + +Prefer concise examples over verbose explanations. + +### Set Appropriate Degrees of Freedom + +Match the level of specificity to the task's fragility and variability: + +**High freedom (text-based instructions)**: Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach. + +**Medium freedom (pseudocode or scripts with parameters)**: Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior. + +**Low freedom (specific scripts, few parameters)**: Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed. + +Think of Claude as exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom). + +### Anatomy of a Skill + +Every skill consists of a required SKILL.md file and optional bundled resources: + +``` +skill-name/ +├── SKILL.md (required) +│ ├── YAML frontmatter metadata (required) +│ │ ├── name: (required) +│ │ └── description: (required) +│ └── Markdown instructions (required) +└── Bundled Resources (optional) + ├── scripts/ - Executable code (Python/Bash/etc.) + ├── references/ - Documentation intended to be loaded into context as needed + └── assets/ - Files used in output (templates, icons, fonts, etc.) +``` + +#### SKILL.md (required) + +Every SKILL.md consists of: + +- **Frontmatter** (YAML): Contains `name` and `description` fields. These are the only fields that Claude reads to determine when the skill gets used, thus it is very important to be clear and comprehensive in describing what the skill is, and when it should be used. +- **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all). + +#### Bundled Resources (optional) + +##### Scripts (`scripts/`) + +Executable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten. + +- **When to include**: When the same code is being rewritten repeatedly or deterministic reliability is needed +- **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks +- **Benefits**: Token efficient, deterministic, may be executed without loading into context +- **Note**: Scripts may still need to be read by Claude for patching or environment-specific adjustments + +##### References (`references/`) + +Documentation and reference material intended to be loaded as needed into context to inform Claude's process and thinking. + +- **When to include**: For documentation that Claude should reference while working +- **Examples**: `references/finance.md` for financial schemas, `references/mnda.md` for company NDA template, `references/policies.md` for company policies, `references/api_docs.md` for API specifications +- **Use cases**: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides +- **Benefits**: Keeps SKILL.md lean, loaded only when Claude determines it's needed +- **Best practice**: If files are large (>10k words), include grep search patterns in SKILL.md +- **Avoid duplication**: Information should live in either SKILL.md or references files, not both. Prefer references files for detailed information unless it's truly core to the skill—this keeps SKILL.md lean while making information discoverable without hogging the context window. Keep only essential procedural instructions and workflow guidance in SKILL.md; move detailed reference material, schemas, and examples to references files. + +##### Assets (`assets/`) + +Files not intended to be loaded into context, but rather used within the output Claude produces. + +- **When to include**: When the skill needs files that will be used in the final output +- **Examples**: `assets/logo.png` for brand assets, `assets/slides.pptx` for PowerPoint templates, `assets/frontend-template/` for HTML/React boilerplate, `assets/font.ttf` for typography +- **Use cases**: Templates, images, icons, boilerplate code, fonts, sample documents that get copied or modified +- **Benefits**: Separates output resources from documentation, enables Claude to use files without loading them into context + +#### What to Not Include in a Skill + +A skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including: + +- README.md +- INSTALLATION_GUIDE.md +- QUICK_REFERENCE.md +- CHANGELOG.md +- etc. + +The skill should only contain the information needed for an AI agent to do the job at hand. It should not contain auxilary context about the process that went into creating it, setup and testing procedures, user-facing documentation, etc. Creating additional documentation files just adds clutter and confusion. + +### Progressive Disclosure Design Principle + +Skills use a three-level loading system to manage context efficiently: + +1. **Metadata (name + description)** - Always in context (~100 words) +2. **SKILL.md body** - When skill triggers (<5k words) +3. **Bundled resources** - As needed by Claude (Unlimited because scripts can be executed without reading into context window) + +#### Progressive Disclosure Patterns + +Keep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit. When splitting out content into other files, it is very important to reference them from SKILL.md and describe clearly when to read them, to ensure the reader of the skill knows they exist and when to use them. + +**Key principle:** When a skill supports multiple variations, frameworks, or options, keep only the core workflow and selection guidance in SKILL.md. Move variant-specific details (patterns, examples, configuration) into separate reference files. + +**Pattern 1: High-level guide with references** + +```markdown +# PDF Processing + +## Quick start + +Extract text with pdfplumber: +[code example] + +## Advanced features + +- **Form filling**: See [FORMS.md](FORMS.md) for complete guide +- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods +- **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns +``` + +Claude loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed. + +**Pattern 2: Domain-specific organization** + +For Skills with multiple domains, organize content by domain to avoid loading irrelevant context: + +``` +bigquery-skill/ +├── SKILL.md (overview and navigation) +└── reference/ + ├── finance.md (revenue, billing metrics) + ├── sales.md (opportunities, pipeline) + ├── product.md (API usage, features) + └── marketing.md (campaigns, attribution) +``` + +When a user asks about sales metrics, Claude only reads sales.md. + +Similarly, for skills supporting multiple frameworks or variants, organize by variant: + +``` +cloud-deploy/ +├── SKILL.md (workflow + provider selection) +└── references/ + ├── aws.md (AWS deployment patterns) + ├── gcp.md (GCP deployment patterns) + └── azure.md (Azure deployment patterns) +``` + +When the user chooses AWS, Claude only reads aws.md. + +**Pattern 3: Conditional details** + +Show basic content, link to advanced content: + +```markdown +# DOCX Processing + +## Creating documents + +Use docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md). + +## Editing documents + +For simple edits, modify the XML directly. + +**For tracked changes**: See [REDLINING.md](REDLINING.md) +**For OOXML details**: See [OOXML.md](OOXML.md) +``` + +Claude reads REDLINING.md or OOXML.md only when the user needs those features. + +**Important guidelines:** + +- **Avoid deeply nested references** - Keep references one level deep from SKILL.md. All reference files should link directly from SKILL.md. +- **Structure longer reference files** - For files longer than 100 lines, include a table of contents at the top so Claude can see the full scope when previewing. + +## Skill Creation Process + +Skill creation involves these steps: + +1. Understand the skill with concrete examples +2. Plan reusable skill contents (scripts, references, assets) +3. Initialize the skill (run init_skill.py) +4. Edit the skill (implement resources and write SKILL.md) +5. Package the skill (run package_skill.py) +6. Iterate based on real usage + +Follow these steps in order, skipping only if there is a clear reason why they are not applicable. + +### Step 1: Understanding the Skill with Concrete Examples + +Skip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill. + +To create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback. + +For example, when building an image-editor skill, relevant questions include: + +- "What functionality should the image-editor skill support? Editing, rotating, anything else?" +- "Can you give some examples of how this skill would be used?" +- "I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?" +- "What would a user say that should trigger this skill?" + +To avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness. + +Conclude this step when there is a clear sense of the functionality the skill should support. + +### Step 2: Planning the Reusable Skill Contents + +To turn concrete examples into an effective skill, analyze each example by: + +1. Considering how to execute on the example from scratch +2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly + +Example: When building a `pdf-editor` skill to handle queries like "Help me rotate this PDF," the analysis shows: + +1. Rotating a PDF requires re-writing the same code each time +2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill + +Example: When designing a `frontend-webapp-builder` skill for queries like "Build me a todo app" or "Build me a dashboard to track my steps," the analysis shows: + +1. Writing a frontend webapp requires the same boilerplate HTML/React each time +2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill + +Example: When building a `big-query` skill to handle queries like "How many users have logged in today?" the analysis shows: + +1. Querying BigQuery requires re-discovering the table schemas and relationships each time +2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill + +To establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets. + +### Step 3: Initializing the Skill + +At this point, it is time to actually create the skill. + +Skip this step only if the skill being developed already exists, and iteration or packaging is needed. In this case, continue to the next step. + +When creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable. + +Usage: + +```bash +python skills/skill-creator/scripts/init_skill.py <skill-name> --path <output-directory> +``` + +The script: + +- Creates the skill directory at the specified path +- Generates a SKILL.md template with proper frontmatter and TODO placeholders +- Creates example resource directories: `scripts/`, `references/`, and `assets/` +- Adds example files in each directory that can be customized or deleted + +After initialization, customize or remove the generated SKILL.md and example files as needed. + +### Step 4: Edit the Skill + +When editing the (newly-generated or existing) skill, remember that the skill is being created for another instance of Claude to use. Include information that would be beneficial and non-obvious to Claude. Consider what procedural knowledge, domain-specific details, or reusable assets would help another Claude instance execute these tasks more effectively. + +#### Learn Proven Design Patterns + +Consult these helpful guides based on your skill's needs: + +- **Multi-step processes**: See references/workflows.md for sequential workflows and conditional logic +- **Specific output formats or quality standards**: See references/output-patterns.md for template and example patterns + +These files contain established best practices for effective skill design. + +#### Start with Reusable Skill Contents + +To begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`. + +Added scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion. + +Any example files and directories not needed for the skill should be deleted. The initialization script creates example files in `scripts/`, `references/`, and `assets/` to demonstrate structure, but most skills won't need all of them. + +#### Update SKILL.md + +**Writing Guidelines:** Always use imperative/infinitive form. + +##### Frontmatter + +Write the YAML frontmatter with `name` and `description`: + +- `name`: The skill name +- `description`: This is the primary triggering mechanism for your skill, and helps Claude understand when to use the skill. + - Include both what the Skill does and specific triggers/contexts for when to use it. + - Include all "when to use" information here - Not in the body. The body is only loaded after triggering, so "When to Use This Skill" sections in the body are not helpful to Claude. + - Example description for a `docx` skill: "Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when Claude needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks" + +Do not include any other fields in YAML frontmatter. + +##### Body + +Write instructions for using the skill and its bundled resources. + +### Step 5: Packaging a Skill + +Once development of the skill is complete, it must be packaged into a distributable .skill file that gets shared with the user. The packaging process automatically validates the skill first to ensure it meets all requirements: + +```bash +python skills/skill-creator/scripts/package_skill.py <path/to/skill-folder> +``` + +Optional output directory specification: + +```bash +python skills/skill-creator/scripts/package_skill.py <path/to/skill-folder> ./dist +``` + +The packaging script will: + +1. **Validate** the skill automatically, checking: + + - YAML frontmatter format and required fields + - Skill naming conventions and directory structure + - Description completeness and quality + - File organization and resource references + +2. **Package** the skill if validation passes, creating a .skill file named after the skill (e.g., `my-skill.skill`) that includes all files and maintains the proper directory structure for distribution. The .skill file is a zip file with a .skill extension. + +If validation fails, the script will report the errors and exit without creating a package. Fix any validation errors and run the packaging command again. + +### Step 6: Iterate + +After testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed. + +**Iteration workflow:** + +1. Use the skill on real tasks +2. Notice struggles or inefficiencies +3. Identify how SKILL.md or bundled resources should be updated +4. Implement changes and test again diff --git a/skills/skill-creator/references/output-patterns.md b/skills/skill-creator/references/output-patterns.md new file mode 100644 index 0000000..073ddda --- /dev/null +++ b/skills/skill-creator/references/output-patterns.md @@ -0,0 +1,82 @@ +# Output Patterns + +Use these patterns when skills need to produce consistent, high-quality output. + +## Template Pattern + +Provide templates for output format. Match the level of strictness to your needs. + +**For strict requirements (like API responses or data formats):** + +```markdown +## Report structure + +ALWAYS use this exact template structure: + +# [Analysis Title] + +## Executive summary +[One-paragraph overview of key findings] + +## Key findings +- Finding 1 with supporting data +- Finding 2 with supporting data +- Finding 3 with supporting data + +## Recommendations +1. Specific actionable recommendation +2. Specific actionable recommendation +``` + +**For flexible guidance (when adaptation is useful):** + +```markdown +## Report structure + +Here is a sensible default format, but use your best judgment: + +# [Analysis Title] + +## Executive summary +[Overview] + +## Key findings +[Adapt sections based on what you discover] + +## Recommendations +[Tailor to the specific context] + +Adjust sections as needed for the specific analysis type. +``` + +## Examples Pattern + +For skills where output quality depends on seeing examples, provide input/output pairs: + +```markdown +## Commit message format + +Generate commit messages following these examples: + +**Example 1:** +Input: Added user authentication with JWT tokens +Output: +``` +feat(auth): implement JWT-based authentication + +Add login endpoint and token validation middleware +``` + +**Example 2:** +Input: Fixed bug where dates displayed incorrectly in reports +Output: +``` +fix(reports): correct date formatting in timezone conversion + +Use UTC timestamps consistently across report generation +``` + +Follow this style: type(scope): brief description, then detailed explanation. +``` + +Examples help Claude understand the desired style and level of detail more clearly than descriptions alone. diff --git a/skills/skill-creator/references/workflows.md b/skills/skill-creator/references/workflows.md new file mode 100644 index 0000000..a350c3c --- /dev/null +++ b/skills/skill-creator/references/workflows.md @@ -0,0 +1,28 @@ +# Workflow Patterns + +## Sequential Workflows + +For complex tasks, break operations into clear, sequential steps. It is often helpful to give Claude an overview of the process towards the beginning of SKILL.md: + +```markdown +Filling a PDF form involves these steps: + +1. Analyze the form (run analyze_form.py) +2. Create field mapping (edit fields.json) +3. Validate mapping (run validate_fields.py) +4. Fill the form (run fill_form.py) +5. Verify output (run verify_output.py) +``` + +## Conditional Workflows + +For tasks with branching logic, guide Claude through decision points: + +```markdown +1. Determine the modification type: + **Creating new content?** → Follow "Creation workflow" below + **Editing existing content?** → Follow "Editing workflow" below + +2. Creation workflow: [steps] +3. Editing workflow: [steps] +``` \ No newline at end of file diff --git a/skills/skill-creator/scripts/init_skill.py b/skills/skill-creator/scripts/init_skill.py new file mode 100755 index 0000000..329ad4e --- /dev/null +++ b/skills/skill-creator/scripts/init_skill.py @@ -0,0 +1,303 @@ +#!/usr/bin/env python3 +""" +Skill Initializer - Creates a new skill from template + +Usage: + init_skill.py <skill-name> --path <path> + +Examples: + init_skill.py my-new-skill --path skills/public + init_skill.py my-api-helper --path skills/private + init_skill.py custom-skill --path /custom/location +""" + +import sys +from pathlib import Path + + +SKILL_TEMPLATE = """--- +name: {skill_name} +description: [TODO: Complete and informative explanation of what the skill does and when to use it. Include WHEN to use this skill - specific scenarios, file types, or tasks that trigger it.] +--- + +# {skill_title} + +## Overview + +[TODO: 1-2 sentences explaining what this skill enables] + +## Structuring This Skill + +[TODO: Choose the structure that best fits this skill's purpose. Common patterns: + +**1. Workflow-Based** (best for sequential processes) +- Works well when there are clear step-by-step procedures +- Example: DOCX skill with "Workflow Decision Tree" → "Reading" → "Creating" → "Editing" +- Structure: ## Overview → ## Workflow Decision Tree → ## Step 1 → ## Step 2... + +**2. Task-Based** (best for tool collections) +- Works well when the skill offers different operations/capabilities +- Example: PDF skill with "Quick Start" → "Merge PDFs" → "Split PDFs" → "Extract Text" +- Structure: ## Overview → ## Quick Start → ## Task Category 1 → ## Task Category 2... + +**3. Reference/Guidelines** (best for standards or specifications) +- Works well for brand guidelines, coding standards, or requirements +- Example: Brand styling with "Brand Guidelines" → "Colors" → "Typography" → "Features" +- Structure: ## Overview → ## Guidelines → ## Specifications → ## Usage... + +**4. Capabilities-Based** (best for integrated systems) +- Works well when the skill provides multiple interrelated features +- Example: Product Management with "Core Capabilities" → numbered capability list +- Structure: ## Overview → ## Core Capabilities → ### 1. Feature → ### 2. Feature... + +Patterns can be mixed and matched as needed. Most skills combine patterns (e.g., start with task-based, add workflow for complex operations). + +Delete this entire "Structuring This Skill" section when done - it's just guidance.] + +## [TODO: Replace with the first main section based on chosen structure] + +[TODO: Add content here. See examples in existing skills: +- Code samples for technical skills +- Decision trees for complex workflows +- Concrete examples with realistic user requests +- References to scripts/templates/references as needed] + +## Resources + +This skill includes example resource directories that demonstrate how to organize different types of bundled resources: + +### scripts/ +Executable code (Python/Bash/etc.) that can be run directly to perform specific operations. + +**Examples from other skills:** +- PDF skill: `fill_fillable_fields.py`, `extract_form_field_info.py` - utilities for PDF manipulation +- DOCX skill: `document.py`, `utilities.py` - Python modules for document processing + +**Appropriate for:** Python scripts, shell scripts, or any executable code that performs automation, data processing, or specific operations. + +**Note:** Scripts may be executed without loading into context, but can still be read by Claude for patching or environment adjustments. + +### references/ +Documentation and reference material intended to be loaded into context to inform Claude's process and thinking. + +**Examples from other skills:** +- Product management: `communication.md`, `context_building.md` - detailed workflow guides +- BigQuery: API reference documentation and query examples +- Finance: Schema documentation, company policies + +**Appropriate for:** In-depth documentation, API references, database schemas, comprehensive guides, or any detailed information that Claude should reference while working. + +### assets/ +Files not intended to be loaded into context, but rather used within the output Claude produces. + +**Examples from other skills:** +- Brand styling: PowerPoint template files (.pptx), logo files +- Frontend builder: HTML/React boilerplate project directories +- Typography: Font files (.ttf, .woff2) + +**Appropriate for:** Templates, boilerplate code, document templates, images, icons, fonts, or any files meant to be copied or used in the final output. + +--- + +**Any unneeded directories can be deleted.** Not every skill requires all three types of resources. +""" + +EXAMPLE_SCRIPT = '''#!/usr/bin/env python3 +""" +Example helper script for {skill_name} + +This is a placeholder script that can be executed directly. +Replace with actual implementation or delete if not needed. + +Example real scripts from other skills: +- pdf/scripts/fill_fillable_fields.py - Fills PDF form fields +- pdf/scripts/convert_pdf_to_images.py - Converts PDF pages to images +""" + +def main(): + print("This is an example script for {skill_name}") + # TODO: Add actual script logic here + # This could be data processing, file conversion, API calls, etc. + +if __name__ == "__main__": + main() +''' + +EXAMPLE_REFERENCE = """# Reference Documentation for {skill_title} + +This is a placeholder for detailed reference documentation. +Replace with actual reference content or delete if not needed. + +Example real reference docs from other skills: +- product-management/references/communication.md - Comprehensive guide for status updates +- product-management/references/context_building.md - Deep-dive on gathering context +- bigquery/references/ - API references and query examples + +## When Reference Docs Are Useful + +Reference docs are ideal for: +- Comprehensive API documentation +- Detailed workflow guides +- Complex multi-step processes +- Information too lengthy for main SKILL.md +- Content that's only needed for specific use cases + +## Structure Suggestions + +### API Reference Example +- Overview +- Authentication +- Endpoints with examples +- Error codes +- Rate limits + +### Workflow Guide Example +- Prerequisites +- Step-by-step instructions +- Common patterns +- Troubleshooting +- Best practices +""" + +EXAMPLE_ASSET = """# Example Asset File + +This placeholder represents where asset files would be stored. +Replace with actual asset files (templates, images, fonts, etc.) or delete if not needed. + +Asset files are NOT intended to be loaded into context, but rather used within +the output Claude produces. + +Example asset files from other skills: +- Brand guidelines: logo.png, slides_template.pptx +- Frontend builder: hello-world/ directory with HTML/React boilerplate +- Typography: custom-font.ttf, font-family.woff2 +- Data: sample_data.csv, test_dataset.json + +## Common Asset Types + +- Templates: .pptx, .docx, boilerplate directories +- Images: .png, .jpg, .svg, .gif +- Fonts: .ttf, .otf, .woff, .woff2 +- Boilerplate code: Project directories, starter files +- Icons: .ico, .svg +- Data files: .csv, .json, .xml, .yaml + +Note: This is a text placeholder. Actual assets can be any file type. +""" + + +def title_case_skill_name(skill_name): + """Convert hyphenated skill name to Title Case for display.""" + return ' '.join(word.capitalize() for word in skill_name.split('-')) + + +def init_skill(skill_name, path): + """ + Initialize a new skill directory with template SKILL.md. + + Args: + skill_name: Name of the skill + path: Path where the skill directory should be created + + Returns: + Path to created skill directory, or None if error + """ + # Determine skill directory path + skill_dir = Path(path).resolve() / skill_name + + # Check if directory already exists + if skill_dir.exists(): + print(f"❌ Error: Skill directory already exists: {skill_dir}") + return None + + # Create skill directory + try: + skill_dir.mkdir(parents=True, exist_ok=False) + print(f"✅ Created skill directory: {skill_dir}") + except Exception as e: + print(f"❌ Error creating directory: {e}") + return None + + # Create SKILL.md from template + skill_title = title_case_skill_name(skill_name) + skill_content = SKILL_TEMPLATE.format( + skill_name=skill_name, + skill_title=skill_title + ) + + skill_md_path = skill_dir / 'SKILL.md' + try: + skill_md_path.write_text(skill_content) + print("✅ Created SKILL.md") + except Exception as e: + print(f"❌ Error creating SKILL.md: {e}") + return None + + # Create resource directories with example files + try: + # Create scripts/ directory with example script + scripts_dir = skill_dir / 'scripts' + scripts_dir.mkdir(exist_ok=True) + example_script = scripts_dir / 'example.py' + example_script.write_text(EXAMPLE_SCRIPT.format(skill_name=skill_name)) + example_script.chmod(0o755) + print("✅ Created scripts/example.py") + + # Create references/ directory with example reference doc + references_dir = skill_dir / 'references' + references_dir.mkdir(exist_ok=True) + example_reference = references_dir / 'api_reference.md' + example_reference.write_text(EXAMPLE_REFERENCE.format(skill_title=skill_title)) + print("✅ Created references/api_reference.md") + + # Create assets/ directory with example asset placeholder + assets_dir = skill_dir / 'assets' + assets_dir.mkdir(exist_ok=True) + example_asset = assets_dir / 'example_asset.txt' + example_asset.write_text(EXAMPLE_ASSET) + print("✅ Created assets/example_asset.txt") + except Exception as e: + print(f"❌ Error creating resource directories: {e}") + return None + + # Print next steps + print(f"\n✅ Skill '{skill_name}' initialized successfully at {skill_dir}") + print("\nNext steps:") + print("1. Edit SKILL.md to complete the TODO items and update the description") + print("2. Customize or delete the example files in scripts/, references/, and assets/") + print("3. Run the validator when ready to check the skill structure") + + return skill_dir + + +def main(): + if len(sys.argv) < 4 or sys.argv[2] != '--path': + print("Usage: init_skill.py <skill-name> --path <path>") + print("\nSkill name requirements:") + print(" - Hyphen-case identifier (e.g., 'data-analyzer')") + print(" - Lowercase letters, digits, and hyphens only") + print(" - Max 40 characters") + print(" - Must match directory name exactly") + print("\nExamples:") + print(" init_skill.py my-new-skill --path skills/public") + print(" init_skill.py my-api-helper --path skills/private") + print(" init_skill.py custom-skill --path /custom/location") + sys.exit(1) + + skill_name = sys.argv[1] + path = sys.argv[3] + + print(f"🚀 Initializing skill: {skill_name}") + print(f" Location: {path}") + print() + + result = init_skill(skill_name, path) + + if result: + sys.exit(0) + else: + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/skills/skill-creator/scripts/package_skill.py b/skills/skill-creator/scripts/package_skill.py new file mode 100755 index 0000000..5cd36cb --- /dev/null +++ b/skills/skill-creator/scripts/package_skill.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +""" +Skill Packager - Creates a distributable .skill file of a skill folder + +Usage: + python utils/package_skill.py <path/to/skill-folder> [output-directory] + +Example: + python utils/package_skill.py skills/public/my-skill + python utils/package_skill.py skills/public/my-skill ./dist +""" + +import sys +import zipfile +from pathlib import Path +from quick_validate import validate_skill + + +def package_skill(skill_path, output_dir=None): + """ + Package a skill folder into a .skill file. + + Args: + skill_path: Path to the skill folder + output_dir: Optional output directory for the .skill file (defaults to current directory) + + Returns: + Path to the created .skill file, or None if error + """ + skill_path = Path(skill_path).resolve() + + # Validate skill folder exists + if not skill_path.exists(): + print(f"❌ Error: Skill folder not found: {skill_path}") + return None + + if not skill_path.is_dir(): + print(f"❌ Error: Path is not a directory: {skill_path}") + return None + + # Validate SKILL.md exists + skill_md = skill_path / "SKILL.md" + if not skill_md.exists(): + print(f"❌ Error: SKILL.md not found in {skill_path}") + return None + + # Run validation before packaging + print("🔍 Validating skill...") + valid, message = validate_skill(skill_path) + if not valid: + print(f"❌ Validation failed: {message}") + print(" Please fix the validation errors before packaging.") + return None + print(f"✅ {message}\n") + + # Determine output location + skill_name = skill_path.name + if output_dir: + output_path = Path(output_dir).resolve() + output_path.mkdir(parents=True, exist_ok=True) + else: + output_path = Path.cwd() + + skill_filename = output_path / f"{skill_name}.skill" + + # Create the .skill file (zip format) + try: + with zipfile.ZipFile(skill_filename, 'w', zipfile.ZIP_DEFLATED) as zipf: + # Walk through the skill directory + for file_path in skill_path.rglob('*'): + if file_path.is_file(): + # Calculate the relative path within the zip + arcname = file_path.relative_to(skill_path.parent) + zipf.write(file_path, arcname) + print(f" Added: {arcname}") + + print(f"\n✅ Successfully packaged skill to: {skill_filename}") + return skill_filename + + except Exception as e: + print(f"❌ Error creating .skill file: {e}") + return None + + +def main(): + if len(sys.argv) < 2: + print("Usage: python utils/package_skill.py <path/to/skill-folder> [output-directory]") + print("\nExample:") + print(" python utils/package_skill.py skills/public/my-skill") + print(" python utils/package_skill.py skills/public/my-skill ./dist") + sys.exit(1) + + skill_path = sys.argv[1] + output_dir = sys.argv[2] if len(sys.argv) > 2 else None + + print(f"📦 Packaging skill: {skill_path}") + if output_dir: + print(f" Output directory: {output_dir}") + print() + + result = package_skill(skill_path, output_dir) + + if result: + sys.exit(0) + else: + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/skills/skill-creator/scripts/quick_validate.py b/skills/skill-creator/scripts/quick_validate.py new file mode 100755 index 0000000..d9fbeb7 --- /dev/null +++ b/skills/skill-creator/scripts/quick_validate.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +""" +Quick validation script for skills - minimal version +""" + +import sys +import os +import re +import yaml +from pathlib import Path + +def validate_skill(skill_path): + """Basic validation of a skill""" + skill_path = Path(skill_path) + + # Check SKILL.md exists + skill_md = skill_path / 'SKILL.md' + if not skill_md.exists(): + return False, "SKILL.md not found" + + # Read and validate frontmatter + content = skill_md.read_text() + if not content.startswith('---'): + return False, "No YAML frontmatter found" + + # Extract frontmatter + match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL) + if not match: + return False, "Invalid frontmatter format" + + frontmatter_text = match.group(1) + + # Parse YAML frontmatter + try: + frontmatter = yaml.safe_load(frontmatter_text) + if not isinstance(frontmatter, dict): + return False, "Frontmatter must be a YAML dictionary" + except yaml.YAMLError as e: + return False, f"Invalid YAML in frontmatter: {e}" + + # Define allowed properties + ALLOWED_PROPERTIES = {'name', 'description', 'license', 'allowed-tools', 'metadata'} + + # Check for unexpected properties (excluding nested keys under metadata) + unexpected_keys = set(frontmatter.keys()) - ALLOWED_PROPERTIES + if unexpected_keys: + return False, ( + f"Unexpected key(s) in SKILL.md frontmatter: {', '.join(sorted(unexpected_keys))}. " + f"Allowed properties are: {', '.join(sorted(ALLOWED_PROPERTIES))}" + ) + + # Check required fields + if 'name' not in frontmatter: + return False, "Missing 'name' in frontmatter" + if 'description' not in frontmatter: + return False, "Missing 'description' in frontmatter" + + # Extract name for validation + name = frontmatter.get('name', '') + if not isinstance(name, str): + return False, f"Name must be a string, got {type(name).__name__}" + name = name.strip() + if name: + # Check naming convention (hyphen-case: lowercase with hyphens) + if not re.match(r'^[a-z0-9-]+$', name): + return False, f"Name '{name}' should be hyphen-case (lowercase letters, digits, and hyphens only)" + if name.startswith('-') or name.endswith('-') or '--' in name: + return False, f"Name '{name}' cannot start/end with hyphen or contain consecutive hyphens" + # Check name length (max 64 characters per spec) + if len(name) > 64: + return False, f"Name is too long ({len(name)} characters). Maximum is 64 characters." + + # Extract and validate description + description = frontmatter.get('description', '') + if not isinstance(description, str): + return False, f"Description must be a string, got {type(description).__name__}" + description = description.strip() + if description: + # Check for angle brackets + if '<' in description or '>' in description: + return False, "Description cannot contain angle brackets (< or >)" + # Check description length (max 1024 characters per spec) + if len(description) > 1024: + return False, f"Description is too long ({len(description)} characters). Maximum is 1024 characters." + + return True, "Skill is valid!" + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage: python quick_validate.py <skill_directory>") + sys.exit(1) + + valid, message = validate_skill(sys.argv[1]) + print(message) + sys.exit(0 if valid else 1) \ No newline at end of file diff --git a/skills/xlsx/LICENSE.txt b/skills/xlsx/LICENSE.txt new file mode 100644 index 0000000..c55ab42 --- /dev/null +++ b/skills/xlsx/LICENSE.txt @@ -0,0 +1,30 @@ +© 2025 Anthropic, PBC. All rights reserved. + +LICENSE: Use of these materials (including all code, prompts, assets, files, +and other components of this Skill) is governed by your agreement with +Anthropic regarding use of Anthropic's services. If no separate agreement +exists, use is governed by Anthropic's Consumer Terms of Service or +Commercial Terms of Service, as applicable: +https://www.anthropic.com/legal/consumer-terms +https://www.anthropic.com/legal/commercial-terms +Your applicable agreement is referred to as the "Agreement." "Services" are +as defined in the Agreement. + +ADDITIONAL RESTRICTIONS: Notwithstanding anything in the Agreement to the +contrary, users may not: + +- Extract these materials from the Services or retain copies of these + materials outside the Services +- Reproduce or copy these materials, except for temporary copies created + automatically during authorized use of the Services +- Create derivative works based on these materials +- Distribute, sublicense, or transfer these materials to any third party +- Make, offer to sell, sell, or import any inventions embodied in these + materials +- Reverse engineer, decompile, or disassemble these materials + +The receipt, viewing, or possession of these materials does not convey or +imply any license or right beyond those expressly granted above. + +Anthropic retains all right, title, and interest in these materials, +including all copyrights, patents, and other intellectual property rights. diff --git a/skills/xlsx/SKILL.md b/skills/xlsx/SKILL.md new file mode 100644 index 0000000..f7144e0 --- /dev/null +++ b/skills/xlsx/SKILL.md @@ -0,0 +1,298 @@ +--- +name: xlsx +description: "Comprehensive spreadsheet creation, editing, and analysis with support for formulas, formatting, data analysis, and visualization. When Claude needs to work with spreadsheets (.xlsx, .xlsm, .csv, .tsv, etc) for: (1) Creating new spreadsheets with formulas and formatting, (2) Reading or analyzing data, (3) Modify existing spreadsheets while preserving formulas, (4) Data analysis and visualization in spreadsheets, or (5) Recalculating formulas" +triggers: + - "excel" + - "spreadsheet" + - "xlsx" + - "csv" + - ".xlsx" + - "formulas" +allowed-tools: Read, Write, Edit, Bash, Glob +version: 1.0.0 +license: Proprietary. LICENSE.txt has complete terms +--- + +# Requirements for Outputs + +## All Excel files + +### Zero Formula Errors +- Every Excel model MUST be delivered with ZERO formula errors (#REF!, #DIV/0!, #VALUE!, #N/A, #NAME?) + +### Preserve Existing Templates (when updating templates) +- Study and EXACTLY match existing format, style, and conventions when modifying files +- Never impose standardized formatting on files with established patterns +- Existing template conventions ALWAYS override these guidelines + +## Financial models + +### Color Coding Standards +Unless otherwise stated by the user or existing template + +#### Industry-Standard Color Conventions +- **Blue text (RGB: 0,0,255)**: Hardcoded inputs, and numbers users will change for scenarios +- **Black text (RGB: 0,0,0)**: ALL formulas and calculations +- **Green text (RGB: 0,128,0)**: Links pulling from other worksheets within same workbook +- **Red text (RGB: 255,0,0)**: External links to other files +- **Yellow background (RGB: 255,255,0)**: Key assumptions needing attention or cells that need to be updated + +### Number Formatting Standards + +#### Required Format Rules +- **Years**: Format as text strings (e.g., "2024" not "2,024") +- **Currency**: Use $#,##0 format; ALWAYS specify units in headers ("Revenue ($mm)") +- **Zeros**: Use number formatting to make all zeros "-", including percentages (e.g., "$#,##0;($#,##0);-") +- **Percentages**: Default to 0.0% format (one decimal) +- **Multiples**: Format as 0.0x for valuation multiples (EV/EBITDA, P/E) +- **Negative numbers**: Use parentheses (123) not minus -123 + +### Formula Construction Rules + +#### Assumptions Placement +- Place ALL assumptions (growth rates, margins, multiples, etc.) in separate assumption cells +- Use cell references instead of hardcoded values in formulas +- Example: Use =B5*(1+$B$6) instead of =B5*1.05 + +#### Formula Error Prevention +- Verify all cell references are correct +- Check for off-by-one errors in ranges +- Ensure consistent formulas across all projection periods +- Test with edge cases (zero values, negative numbers) +- Verify no unintended circular references + +#### Documentation Requirements for Hardcodes +- Comment or in cells beside (if end of table). Format: "Source: [System/Document], [Date], [Specific Reference], [URL if applicable]" +- Examples: + - "Source: Company 10-K, FY2024, Page 45, Revenue Note, [SEC EDGAR URL]" + - "Source: Company 10-Q, Q2 2025, Exhibit 99.1, [SEC EDGAR URL]" + - "Source: Bloomberg Terminal, 8/15/2025, AAPL US Equity" + - "Source: FactSet, 8/20/2025, Consensus Estimates Screen" + +# XLSX creation, editing, and analysis + +## Overview + +A user may ask you to create, edit, or analyze the contents of an .xlsx file. You have different tools and workflows available for different tasks. + +## Important Requirements + +**LibreOffice Required for Formula Recalculation**: You can assume LibreOffice is installed for recalculating formula values using the `recalc.py` script. The script automatically configures LibreOffice on first run + +## Reading and analyzing data + +### Data analysis with pandas +For data analysis, visualization, and basic operations, use **pandas** which provides powerful data manipulation capabilities: + +```python +import pandas as pd + +# Read Excel +df = pd.read_excel('file.xlsx') # Default: first sheet +all_sheets = pd.read_excel('file.xlsx', sheet_name=None) # All sheets as dict + +# Analyze +df.head() # Preview data +df.info() # Column info +df.describe() # Statistics + +# Write Excel +df.to_excel('output.xlsx', index=False) +``` + +## Excel File Workflows + +## CRITICAL: Use Formulas, Not Hardcoded Values + +**Always use Excel formulas instead of calculating values in Python and hardcoding them.** This ensures the spreadsheet remains dynamic and updateable. + +### ❌ WRONG - Hardcoding Calculated Values +```python +# Bad: Calculating in Python and hardcoding result +total = df['Sales'].sum() +sheet['B10'] = total # Hardcodes 5000 + +# Bad: Computing growth rate in Python +growth = (df.iloc[-1]['Revenue'] - df.iloc[0]['Revenue']) / df.iloc[0]['Revenue'] +sheet['C5'] = growth # Hardcodes 0.15 + +# Bad: Python calculation for average +avg = sum(values) / len(values) +sheet['D20'] = avg # Hardcodes 42.5 +``` + +### ✅ CORRECT - Using Excel Formulas +```python +# Good: Let Excel calculate the sum +sheet['B10'] = '=SUM(B2:B9)' + +# Good: Growth rate as Excel formula +sheet['C5'] = '=(C4-C2)/C2' + +# Good: Average using Excel function +sheet['D20'] = '=AVERAGE(D2:D19)' +``` + +This applies to ALL calculations - totals, percentages, ratios, differences, etc. The spreadsheet should be able to recalculate when source data changes. + +## Common Workflow +1. **Choose tool**: pandas for data, openpyxl for formulas/formatting +2. **Create/Load**: Create new workbook or load existing file +3. **Modify**: Add/edit data, formulas, and formatting +4. **Save**: Write to file +5. **Recalculate formulas (MANDATORY IF USING FORMULAS)**: Use the recalc.py script + ```bash + python recalc.py output.xlsx + ``` +6. **Verify and fix any errors**: + - The script returns JSON with error details + - If `status` is `errors_found`, check `error_summary` for specific error types and locations + - Fix the identified errors and recalculate again + - Common errors to fix: + - `#REF!`: Invalid cell references + - `#DIV/0!`: Division by zero + - `#VALUE!`: Wrong data type in formula + - `#NAME?`: Unrecognized formula name + +### Creating new Excel files + +```python +# Using openpyxl for formulas and formatting +from openpyxl import Workbook +from openpyxl.styles import Font, PatternFill, Alignment + +wb = Workbook() +sheet = wb.active + +# Add data +sheet['A1'] = 'Hello' +sheet['B1'] = 'World' +sheet.append(['Row', 'of', 'data']) + +# Add formula +sheet['B2'] = '=SUM(A1:A10)' + +# Formatting +sheet['A1'].font = Font(bold=True, color='FF0000') +sheet['A1'].fill = PatternFill('solid', start_color='FFFF00') +sheet['A1'].alignment = Alignment(horizontal='center') + +# Column width +sheet.column_dimensions['A'].width = 20 + +wb.save('output.xlsx') +``` + +### Editing existing Excel files + +```python +# Using openpyxl to preserve formulas and formatting +from openpyxl import load_workbook + +# Load existing file +wb = load_workbook('existing.xlsx') +sheet = wb.active # or wb['SheetName'] for specific sheet + +# Working with multiple sheets +for sheet_name in wb.sheetnames: + sheet = wb[sheet_name] + print(f"Sheet: {sheet_name}") + +# Modify cells +sheet['A1'] = 'New Value' +sheet.insert_rows(2) # Insert row at position 2 +sheet.delete_cols(3) # Delete column 3 + +# Add new sheet +new_sheet = wb.create_sheet('NewSheet') +new_sheet['A1'] = 'Data' + +wb.save('modified.xlsx') +``` + +## Recalculating formulas + +Excel files created or modified by openpyxl contain formulas as strings but not calculated values. Use the provided `recalc.py` script to recalculate formulas: + +```bash +python recalc.py <excel_file> [timeout_seconds] +``` + +Example: +```bash +python recalc.py output.xlsx 30 +``` + +The script: +- Automatically sets up LibreOffice macro on first run +- Recalculates all formulas in all sheets +- Scans ALL cells for Excel errors (#REF!, #DIV/0!, etc.) +- Returns JSON with detailed error locations and counts +- Works on both Linux and macOS + +## Formula Verification Checklist + +Quick checks to ensure formulas work correctly: + +### Essential Verification +- [ ] **Test 2-3 sample references**: Verify they pull correct values before building full model +- [ ] **Column mapping**: Confirm Excel columns match (e.g., column 64 = BL, not BK) +- [ ] **Row offset**: Remember Excel rows are 1-indexed (DataFrame row 5 = Excel row 6) + +### Common Pitfalls +- [ ] **NaN handling**: Check for null values with `pd.notna()` +- [ ] **Far-right columns**: FY data often in columns 50+ +- [ ] **Multiple matches**: Search all occurrences, not just first +- [ ] **Division by zero**: Check denominators before using `/` in formulas (#DIV/0!) +- [ ] **Wrong references**: Verify all cell references point to intended cells (#REF!) +- [ ] **Cross-sheet references**: Use correct format (Sheet1!A1) for linking sheets + +### Formula Testing Strategy +- [ ] **Start small**: Test formulas on 2-3 cells before applying broadly +- [ ] **Verify dependencies**: Check all cells referenced in formulas exist +- [ ] **Test edge cases**: Include zero, negative, and very large values + +### Interpreting recalc.py Output +The script returns JSON with error details: +```json +{ + "status": "success", // or "errors_found" + "total_errors": 0, // Total error count + "total_formulas": 42, // Number of formulas in file + "error_summary": { // Only present if errors found + "#REF!": { + "count": 2, + "locations": ["Sheet1!B5", "Sheet1!C10"] + } + } +} +``` + +## Best Practices + +### Library Selection +- **pandas**: Best for data analysis, bulk operations, and simple data export +- **openpyxl**: Best for complex formatting, formulas, and Excel-specific features + +### Working with openpyxl +- Cell indices are 1-based (row=1, column=1 refers to cell A1) +- Use `data_only=True` to read calculated values: `load_workbook('file.xlsx', data_only=True)` +- **Warning**: If opened with `data_only=True` and saved, formulas are replaced with values and permanently lost +- For large files: Use `read_only=True` for reading or `write_only=True` for writing +- Formulas are preserved but not evaluated - use recalc.py to update values + +### Working with pandas +- Specify data types to avoid inference issues: `pd.read_excel('file.xlsx', dtype={'id': str})` +- For large files, read specific columns: `pd.read_excel('file.xlsx', usecols=['A', 'C', 'E'])` +- Handle dates properly: `pd.read_excel('file.xlsx', parse_dates=['date_column'])` + +## Code Style Guidelines +**IMPORTANT**: When generating Python code for Excel operations: +- Write minimal, concise Python code without unnecessary comments +- Avoid verbose variable names and redundant operations +- Avoid unnecessary print statements + +**For Excel files themselves**: +- Add comments to cells with complex formulas or important assumptions +- Document data sources for hardcoded values +- Include notes for key calculations and model sections \ No newline at end of file diff --git a/skills/xlsx/recalc.py b/skills/xlsx/recalc.py new file mode 100755 index 0000000..102e157 --- /dev/null +++ b/skills/xlsx/recalc.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 +""" +Excel Formula Recalculation Script +Recalculates all formulas in an Excel file using LibreOffice +""" + +import json +import sys +import subprocess +import os +import platform +from pathlib import Path +from openpyxl import load_workbook + + +def setup_libreoffice_macro(): + """Setup LibreOffice macro for recalculation if not already configured""" + if platform.system() == 'Darwin': + macro_dir = os.path.expanduser('~/Library/Application Support/LibreOffice/4/user/basic/Standard') + else: + macro_dir = os.path.expanduser('~/.config/libreoffice/4/user/basic/Standard') + + macro_file = os.path.join(macro_dir, 'Module1.xba') + + if os.path.exists(macro_file): + with open(macro_file, 'r') as f: + if 'RecalculateAndSave' in f.read(): + return True + + if not os.path.exists(macro_dir): + subprocess.run(['soffice', '--headless', '--terminate_after_init'], + capture_output=True, timeout=10) + os.makedirs(macro_dir, exist_ok=True) + + macro_content = '''<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd"> +<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Module1" script:language="StarBasic"> + Sub RecalculateAndSave() + ThisComponent.calculateAll() + ThisComponent.store() + ThisComponent.close(True) + End Sub +</script:module>''' + + try: + with open(macro_file, 'w') as f: + f.write(macro_content) + return True + except Exception: + return False + + +def recalc(filename, timeout=30): + """ + Recalculate formulas in Excel file and report any errors + + Args: + filename: Path to Excel file + timeout: Maximum time to wait for recalculation (seconds) + + Returns: + dict with error locations and counts + """ + if not Path(filename).exists(): + return {'error': f'File {filename} does not exist'} + + abs_path = str(Path(filename).absolute()) + + if not setup_libreoffice_macro(): + return {'error': 'Failed to setup LibreOffice macro'} + + cmd = [ + 'soffice', '--headless', '--norestore', + 'vnd.sun.star.script:Standard.Module1.RecalculateAndSave?language=Basic&location=application', + abs_path + ] + + # Handle timeout command differences between Linux and macOS + if platform.system() != 'Windows': + timeout_cmd = 'timeout' if platform.system() == 'Linux' else None + if platform.system() == 'Darwin': + # Check if gtimeout is available on macOS + try: + subprocess.run(['gtimeout', '--version'], capture_output=True, timeout=1, check=False) + timeout_cmd = 'gtimeout' + except (FileNotFoundError, subprocess.TimeoutExpired): + pass + + if timeout_cmd: + cmd = [timeout_cmd, str(timeout)] + cmd + + result = subprocess.run(cmd, capture_output=True, text=True) + + if result.returncode != 0 and result.returncode != 124: # 124 is timeout exit code + error_msg = result.stderr or 'Unknown error during recalculation' + if 'Module1' in error_msg or 'RecalculateAndSave' not in error_msg: + return {'error': 'LibreOffice macro not configured properly'} + else: + return {'error': error_msg} + + # Check for Excel errors in the recalculated file - scan ALL cells + try: + wb = load_workbook(filename, data_only=True) + + excel_errors = ['#VALUE!', '#DIV/0!', '#REF!', '#NAME?', '#NULL!', '#NUM!', '#N/A'] + error_details = {err: [] for err in excel_errors} + total_errors = 0 + + for sheet_name in wb.sheetnames: + ws = wb[sheet_name] + # Check ALL rows and columns - no limits + for row in ws.iter_rows(): + for cell in row: + if cell.value is not None and isinstance(cell.value, str): + for err in excel_errors: + if err in cell.value: + location = f"{sheet_name}!{cell.coordinate}" + error_details[err].append(location) + total_errors += 1 + break + + wb.close() + + # Build result summary + result = { + 'status': 'success' if total_errors == 0 else 'errors_found', + 'total_errors': total_errors, + 'error_summary': {} + } + + # Add non-empty error categories + for err_type, locations in error_details.items(): + if locations: + result['error_summary'][err_type] = { + 'count': len(locations), + 'locations': locations[:20] # Show up to 20 locations + } + + # Add formula count for context - also check ALL cells + wb_formulas = load_workbook(filename, data_only=False) + formula_count = 0 + for sheet_name in wb_formulas.sheetnames: + ws = wb_formulas[sheet_name] + for row in ws.iter_rows(): + for cell in row: + if cell.value and isinstance(cell.value, str) and cell.value.startswith('='): + formula_count += 1 + wb_formulas.close() + + result['total_formulas'] = formula_count + + return result + + except Exception as e: + return {'error': str(e)} + + +def main(): + if len(sys.argv) < 2: + print("Usage: python recalc.py <excel_file> [timeout_seconds]") + print("\nRecalculates all formulas in an Excel file using LibreOffice") + print("\nReturns JSON with error details:") + print(" - status: 'success' or 'errors_found'") + print(" - total_errors: Total number of Excel errors found") + print(" - total_formulas: Number of formulas in the file") + print(" - error_summary: Breakdown by error type with locations") + print(" - #VALUE!, #DIV/0!, #REF!, #NAME?, #NULL!, #NUM!, #N/A") + sys.exit(1) + + filename = sys.argv[1] + timeout = int(sys.argv[2]) if len(sys.argv) > 2 else 30 + + result = recalc(filename, timeout) + print(json.dumps(result, indent=2)) + + +if __name__ == '__main__': + main() \ No newline at end of file