{"id":18825380,"url":"https://github.com/outsystems/ultimatepdf-externallogic","last_synced_at":"2026-01-20T23:30:18.758Z","repository":{"id":212063692,"uuid":"660569659","full_name":"OutSystems/UltimatePDF-ExternalLogic","owner":"OutSystems","description":"Port of UltimatePDF to ODC External Library","archived":false,"fork":false,"pushed_at":"2025-02-13T13:19:31.000Z","size":175198,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-13T14:26:57.842Z","etag":null,"topics":["snyk-vanguard"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OutSystems.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-30T09:55:41.000Z","updated_at":"2025-02-02T03:33:43.000Z","dependencies_parsed_at":"2023-12-12T11:26:55.463Z","dependency_job_id":"d919c5f2-248c-4533-b3b3-4a6524f25eb8","html_url":"https://github.com/OutSystems/UltimatePDF-ExternalLogic","commit_stats":null,"previous_names":["outsystems/ultimatepdf-externallogic"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OutSystems%2FUltimatePDF-ExternalLogic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OutSystems%2FUltimatePDF-ExternalLogic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OutSystems%2FUltimatePDF-ExternalLogic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OutSystems%2FUltimatePDF-ExternalLogic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OutSystems","download_url":"https://codeload.github.com/OutSystems/UltimatePDF-ExternalLogic/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239763667,"owners_count":19692800,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["snyk-vanguard"],"created_at":"2024-11-08T00:59:16.757Z","updated_at":"2026-01-20T23:30:18.688Z","avatar_url":"https://github.com/OutSystems.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca name=\"readme-top\"\u003e\u003c/a\u003e\n\n\u003c!-- PROJECT LOGO --\u003e\n\u003cbr /\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://github.com/OutSystems/ODC-VG-UltimatePDF-Service\"\u003e\n    \u003cimg src=\"images/PrintLayout.png\" alt=\"Logo\" width=\"80\" height=\"80\" /\u003e\n  \u003c/a\u003e\n\n  \u003ch3 align=\"center\"\u003e\u003cb\u003eUltimate PDF\u003c/b\u003e\u003c/h3\u003e\n  \n  \u003cp align=\"center\"\u003e\n    Generate PDF reports by using modern web technologies.\n  \u003c/p\u003e\n\u003c/div\u003e\n\n\u003c!-- TABLE OF CONTENTS --\u003e\n\u003cdetails open\u003e\n  \u003csummary\u003eTable of Contents\u003c/summary\u003e\n  \u003col\u003e\n    \u003cli\u003e\u003ca href=\"#about-the-project\"\u003eAbout The Project\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\n      \u003ca href=\"#getting-started\"\u003eGetting Started\u003c/a\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#prerequisites\"\u003ePrerequisites\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#installation\"\u003eInstallation\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#usage\"\u003eUsage\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\n      \u003ca href=\"#advance-scenarios\"\u003eAdvance Scenarios\u003c/a\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#prerequisites-1\"\u003ePrerequisites\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#advance-pdf-generation\"\u003eAdvance PDF Generation\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#screen-to-pdf\"\u003eScreen to PDF\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#external-logic-call-rest-api-to-store-the-pdf\"\u003eExternal Logic call Rest API to store the PDF\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#external-logic-call-s3-bucket-to-store-the-pdf\"\u003eExternal Logic call S3 Bucket to store the PDF\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#basic-page-screenshot\"\u003eBasic page screenshot\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#add-fonts-to-the-report\"\u003eAdd Fonts to the Report\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#license\"\u003eLicense\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#known-limitations\"\u003eKnown Limitations\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#get-in-touch\"\u003eGet in touch\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#contributing\"\u003eContributing\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#testing\"\u003eTesting\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#acknowledgments\"\u003eAcknowledgments\u003c/a\u003e\u003c/li\u003e\n  \u003c/ol\u003e\n\u003c/details\u003e\n\n## About The Project\n\nProject that enables ODC customers to generate PDFs using modern web technologies.\n\nThis component uses the same rendering engine as Chromium (an open-source version of Google Chrome) to transform web pages into PDF documents.\n\nThis component is based on the O11 version of \u003ca href=\"https://www.outsystems.com/forge/component-overview/5641/ultimate-pdf\"\u003eUltimate PDF\u003c/a\u003e.\n\n\u003cb\u003eTHIS CODE IS NOT SUPPORTED BY OUTSYSTEMS.\u003c/b\u003e\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Getting Started\n\nThis repo contains all the external code (C#) and the modules that can be used to accelerate the development of PDFs at ODC Applications.\n\n### Prerequisites\n\nTo generate the External Logic package run \n```sh\n.\\generate_upload_package.ps1\n```\n\n### Installation\n\nThis component is published at forge. So the best way to install it on your ODC tenant is by searching for:\n* UltimatePDF_ExternalLogic\n* Ultimate PDF\n* _(Optional)_ Template_UltimatePDF\n\n#### From the repo\n\nThe code will generate the file `UltimatePDF_ExternalLogic.zip` that can be uploaded to the ODC Portal as external logic (\u003ca href=\"https://success.outsystems.com/documentation/outsystems_developer_cloud/building_apps/extend_your_apps_with_external_logic_using_custom_code/\"\u003edocumentation\u003c/a\u003e).\n\nUse ODC Studio to publish the modules\n* Ultimate PDF.oml - Library with accelerators to use the code from the External Logic actions\n* Template_UltimatePDF.oml - Application template. Use this template to create an application that is ready to use the Ultimate PDF component\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Usage\n\nThe simplest way to generate a PDF is by:\n\n1. Create an empty screen\n1. Add to the screen the web block `PrintLayout` (from UltimatePDF)\n1. Build the report\n1. Call the server action `PrintToPDF` to generate the PDF (from UltimatePDF)\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Public Elements\n\nAll the listed public elements are present in the library **Ultimate PDF**.\n\n### Block\n\n- **PageCount**: Displays the total number of pages. Use inside the header of footer of PrintLayout.  See also: PrintLayout.\n- **PageNumber**: Displays the current page number. Use inside the header of footer of PrintLayout.  See also: PrintLayout.\n- **PageBreak**: Force a page break.\n- **SectionBreak**: Breaks a section between two PrintLayout blocks, and allows to control how pagination continues on the new section.\n- **PrintLayout**: Creates a page layout, including header and footer placeholders that are repeated on every page, and a page background that can be used for watermarks and other full-bleed design elements.  See also: ScreenToPDF.\n- **ScreenToPDF**: Automatically converts a screen into PDF, such that any navigation to the screen automatically downloads it as a PDF.\n- **HideOnPrint**: Content will not be shown on print media.\n- **ShowOnPrint**: Content will only be shown on print media.\n\n### Client actions\n\n- **OnApplicationReady_UltimatePDF**: Loads support for Ultimate PDF on reactive applications.  This action must be invoked during the OnApplicationReady event. Some features of Ultimate PDF may not work otherwise.\n- **ScreenToPDF_OnInitialize**: Initializes a screen that is using ScreenToPDF block.  This action must be invoked during the OnInitialize event of the screen. The ScreenToPDF block will not work otherwise.\n- **CurrEnvironment**: Current Environment information.\n- **GetDefaultViewport**: Defines a default viewport size of 1366x768\n\n### Server actions\n\n- **PrintToPDF**: Generates a PDF from a given URL, using the paper size and margin size from the print stylesheet.\n- **PrintToPDF_Advanced**: Generates a PDF from a given URL, specifying paper size and margin size.\n- **ScreenshotToPNG**: Generates a screenshot (PNG) from a given URL, using the paper size and margin size from the print stylesheet.\n- **ScreenshotToPNG_Advanced**: Generates a screenshot (PNG) from a given URL, specifying paper size and margin size.\n- **GetDefaultViewport**: Defines a default viewport size of 1366x768\n\n### Static Entities\n\n- **MarginSize**: Common document margin sizes.\n- **PaperSize**: Common paper sizes.\n\n## Advance Scenarios\n\n### Prerequisites\n\nIn the instructions bellow we will assume that the application that is generating the PDFs was created based on Template_UltimatePDF. This Template creates an application that contains:\n* REST API `pdf` - that implements an API to store the PDF on the application\n* Entity `GeneratePDF` - contains information for the pdf and the token authentication for the the pages\n* Entity `GeneratedPDF_Files` - entity where the REST API saves the PDF files\n* Entity `GeneratedPDF_Logs` - entity where the REST API saves the Log files\n\n### Advance PDF Generation\n\n1. Create a Flow named *Print*, if not present\n1. Add an empty screen\n1. Under the Authorization properties, select `Everyone`\n1. Add an input parameter named `Token` (Data Type = Text, Is Mandatory = Yes)\n1. Delete the web block `Layouts\\LayoutTopMenu`\n1. Fill the screen with the information to have in the PDF\n1. Add `On Initialize` event, and add a call to IsPDFTokenValid with the `Token` as parameter\n1. Add a if clause `IsPDFTokeValid.Valid`, and end the *False* branch with and exception `PDFTokenExpired`\n1. Add `On Ready` event, and add a call to `ExpireToken` with the `Token` as parameter\n1. On another screen create a button to generate the PDF\n1. Call the Server Action `GeneratePDFToken`\n1. Call the Server Action `PrintToPDF_Advanced`\n  * URL - url for the page to be generated. In this example, the screen was created at _2._\n  * Environment - information of the environment where the browser will be launched. Can use the output of the Client Action `CurrEnvironment`\n  * PaperSize - Paper size measures separated by _x_ (eg: \"21.00x29.70\"). Can use the Static Entity `PaperSize` from `UltimatePDF`\n  * MarginSize - Paper margin size separated by _x_ (eg: \"2.50x3.00x2.50x3.00\"). Can use the Static Entity `MarginSize` from `UltimatePDF`\n  * CollectLogs - If the execution of the external logic collects logs. If True, the output parameter LogsZipFile has the logs, it's empty otherwise.\n  * Cookies - Cookie values to be used in the browser that will be launched.\n  * TimeoutSeconds - Timeout in seconds the browser will wait to render and generate the PDF\n  * RestCaller - REST API information for the external logic to store the PDF and the LogsZipFile.\n  * PDF _(Output parameter)_ - The PDF file binary data. Empty if RestCaller is passed.\n  * LogsZipFile _(Output parameter)_ - The logs of the external logic execution. Empty if RestCaller is passed.\n1. Call Download with the output parameter *PDF* of the Server Action `PrintToPDF_Advanced`\n\n\u003cimg src=\"images/OnInitialize.png\" width=\"200\" height=\"auto\"/\u003e\u003cimg src=\"images/OnClick.png\" width=\"200\" height=\"auto\"/\u003e\n\n### Screen to PDF\n\n1. At the Logic table add a System Event \u003e On Application Ready\n1. Add a call to `OnApplicationReady_UltimatePDF`\n1. Create a Flow named *Print*, if not present\n1. Add an empty screen\n1. Under the Authorization properties, select `Everyone`\n1. Add an input parameter named `Token` (Data Type = Text, Is Mandatory = Yes)\n1. Delete the web block `Layouts\\LayoutTopMenu`\n1. Add the web block `PrintLayout\\ScreenToPDF`\n1. Fill the screen with the information to have in the PDF\n1. Add `On Initialize` event, and add a call to `IsPDFTokenValid` with the `Token` as parameter\n1. Add a if clause `IsPDFTokeValid.Valid`, and end the *False* branch with and exception `PDFTokenExpired`\n1. Add a call to `ScreenToPDF_OnInitialize`\n1. Add `On Ready` event, and add a call to `ExpireToken` with the `Token` as parameter\n1. On another screen create a link with an action on click\n1. Call the Server Action `GeneratePDFToken`\n1. End the flow with a destination to the screen created at 2.\n\n\u003cimg src=\"images/OnApplicationReadyScreen.png\" width=\"200\" height=\"auto\"/\u003e\u003cimg src=\"images/OnInitializeScreen.png\" width=\"200\" height=\"auto\"/\u003e\u003cimg src=\"images/OnReadyScreen.png\" width=\"200\" height=\"auto\"/\u003e\u003cimg src=\"images/OnClickScreen.png\" width=\"200\" height=\"auto\"/\u003e\n\n### External Logic call Rest API to store the PDF\n\nThe Template_UltimatePDF already creates a REST API named *pdf* with two methods *Store* and *StoreLogs*. The external logic expects the REST API to be implemented as POST methods with binary data as the body of the request. The API call uses the `Token` parameter as an authorization header.\n\n1. Create a Flow named *Print*, if not present\n1. Add an empty screen\n1. Under the Authorization properties, select `Everyone`\n1. Add an input parameter named `Token` (Data Type = Text, Is Mandatory = Yes)\n1. Delete the web block `Layouts\\LayoutTopMenu`\n1. Fill the screen with the information to have in the PDF\n1. Add `On Initialize` event, and add a call to IsPDFTokenValid with the `Token` as parameter\n1. Add a if clause `IsPDFTokeValid.Valid`, and end the *False* branch with and exception `PDFTokenExpired`\n1. On another screen create a button to generate the PDF\n1. Call the Server Action `GeneratePDFToken`\n1. Call the Server Action `PrintToPDF_Advanced_ToRest`, fill the RestCaller parameter\n  * Token - The token of the printable page, we use it for REST API authentication.\n  * BaseUrl - base tenant url, eg: _https://tenant.outsystems.com_\n  * Module - Name of the module that implements the REST API, can use `GetOwnerURLPath()`\n  * StorePath - Rest method URL Path to store the PDF, eg: `/rest/pdf/Store`\n  * LogPath - Rest method URL Path to store the logs, eg: `/rest/pdf/StoreLogs`\n  * The PDF will be stored at the entity `GeneratedPDF_Files`\n  * The Logs will be stored at the entity `GeneratedPDF_Logs`, if requested\n\n### External Logic call S3 Bucket to store the PDF\n\nMore information on S3 buckets and presigned urls can be found in official \u003ca href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html\"\u003eAWS documentation\u003c/a\u003e.\n\n1. Create a Flow named *Print*, if not present\n1. Add an empty screen\n1. Under the Authorization properties, select `Everyone`\n1. Add an input parameter named `Token` (Data Type = Text, Is Mandatory = Yes)\n1. Delete the web block `Layouts\\LayoutTopMenu`\n1. Fill the screen with the information to have in the PDF\n1. Add `On Initialize` event, and add a call to IsPDFTokenValid with the `Token` as parameter\n1. Add a if clause `IsPDFTokeValid.Valid`, and end the *False* branch with and exception `PDFTokenExpired`\n1. On another screen create a button to generate the PDF\n1. Call the Server Action `GeneratePDFToken`\n1. Call the Server Action `PrintToPDF_Advanced_ToS3`, fill the S3Endpoints parameter\n  * PdfPreSignedUrl - Presigned url to a S3 Bucket to store the resulting PDF\n  * LogsPreSignedUrl - Presigned url to a S3 Bucket to store the resulting logs\n\n### Basic page screenshot\n\n1. Create an empty screen\n1. Add to the screen the web block `PrintLayout` (from UltimatePDF)\n1. Build the report\n1. Call the server action `ScreenshotToPNG` to generate the image (from UltimatePDF)\n\n\u003cimg src=\"images/screenshot.png\"/\u003e\n\n### Add Fonts to the Report\n\nThe library uses \u003ca href=\"https://developers.google.com/fonts/docs/getting_started\"\u003eGoogle Fonts\u003c/a\u003e to download the fonts for the PDF generation. Fonts added using these methods need to be available in the Google Fonts.\n\n1. At the report page on the OnInitialize action add `SetDocumentFont`\n1. If the font you need is not present on the static entity `Fonts`, call the `AddFontFamilyToDocument` to the add the custom font.\n\n## License\n\nBSD-3 license. See \u003ca href=\"LICENSE\"\u003eLICENSE\u003c/a\u003e for more information.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Known Limitations\n\n* Ultimate PDF doesn’t support the \u003ca href=\"https://success.outsystems.com/documentation/outsystems_developer_cloud/managing_outsystems_platform_and_apps/configure_ip_filters/\"\u003eIP Filtering\u003c/a\u003e feature. Enabling this feature in a stage will result in the reports returning a 403 error page. According to OutSystems \u003ca href=\"https://success.outsystems.com/documentation/outsystems_developer_cloud/building_apps/extend_your_apps_with_external_logic_using_custom_code/external_libraries_sdk_readme/\"\u003edocumentation\u003c/a\u003e, the external libraries run on “an external service” outside the realm of the tenant applications. Because of this, Ultimate PDF fails to call the report page to render the PDF.\n* The screens to print cannot be protected by authentication. We recommend the screens to be protected by tokens. See the usage of `GeneratePDFToken` on this documentation for examples.\n* The input and output payload of the external logic cannot be greater than 5.5MB. \u003ca href=\"#external-logic-call-rest-api-to-store-the-pdf\"\u003eWorkaround use the REST API Store functionality\u003c/a\u003e.\n* The version of chromium bundle with the forge component only has \u003ca href=\"https://fonts.google.com/specimen/Open+Sans?query=open+sans\"\u003eOpen Sans font\u003c/a\u003e installed meaning it only supports a subset of languages. As a \u003ca href=\"#add-fonts-to-the-report\"\u003eworkaround\u003c/a\u003e the customer can add the needed fonts as css (\u003ca href=\"https://developers.google.com/fonts/docs/getting_started\"\u003ehttps://developers.google.com/fonts/docs/getting_started\u003c/a\u003e).\n* ODC has a time limit for running external logic (custom code). The current configuration is 95 seconds (\u003ca href=\"https://success.outsystems.com/documentation/outsystems_developer_cloud/getting_started/outsystems_system_requirements_for_odc/#platform-limits\"\u003edocumentation\u003c/a\u003e). Any call to this library that takes more than 95 seconds will fail with a timeout. If you are getting a 95 seconds timeout please consider: 1) Reviewing the report (screen) logic to try and improve its performance; 2) using a different library that does not rely on rendering the page on demand to generate the PDF. \n  * To check if you are affected by this check the \u003ca href=\"https://success.outsystems.com/documentation/outsystems_developer_cloud/monitoring_and_troubleshooting_apps/\"\u003eTraces\u003c/a\u003e to see if you have a message like \u003ci\u003e\"OS-BERT-ELR-61302 - Running this action's custom code has exceeded the timeout limit of 95 seconds.\"\u003c/i\u003e.\n* Rendering multiple instances of the \u003ca href=\"https://success.outsystems.com/documentation/outsystems_developer_cloud/building_apps/user_interface/patterns/interaction/map/\"\u003eMap widget\u003c/a\u003e have been reported and tested as not working correctly when generating a PDF or Screenshot.\n  * A workaround for this problem is using \u003ca href=\"https://outsystemsui.outsystems.com/OutSystemsMapsSample/StaticMap\"\u003eStatic map\u003c/a\u003e, which we advise as a more efficient component to use in reports.\n* The first execution of the UltimatePDF external logic normally is slower than 10 seconds. This results in the request timing out. The main reason for this slowness is the fact that we need to prepare a chromium browser to run the requests, and then the render of the page. In an interval of 10 to 15 minutes this penalty is reduced since the external logic infrastructure is reused. The best workaround for this limitation is to set a Server Request Timeout greater than 10 seconds. \n  * To check if you are affected by this check the \u003ca href=\"https://success.outsystems.com/documentation/outsystems_developer_cloud/monitoring_and_troubleshooting_apps/\"\u003eTraces\u003c/a\u003e to see if you have a timeout.\n\n\u003cimg src=\"images/ServerRequestTimeout.png\" width=\"200\" height=\"auto\"/\u003e\u003cimg src=\"images/TimeoutTrace.png\" width=\"200\" height=\"auto\"/\u003e\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Get in touch\n\nHelp us improve `UltimatePDF-ExternalLogic` by either:\n* \u003ca href=\"https://github.com/OutSystems/UltimatePDF-ExternalLogic/issues\"\u003eSubmitting an issue\u003c/a\u003e with detailed information about the problem you're having\n* \u003ca href=\"mailto:vanguard@outsystems.com\"\u003eSending us an email\u003c/a\u003e with any feedback or questions that you may have\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Contributing\n\n1. Do a repository Fork;\n1. Create a branch based in the branch master (latest \u0026 greatest release);\n1. Open the branch with you favorite C# code editor;\n1. Make your code change;\n1. Document your code;\n1. Install the external logic in your tenant and test;\n1. Kept the branch updated with the master branch and also synchronized with the upstream master;\n1. Create a PR, describing what was the (mis)behavior, what you changed and please provide a sample;\n1. Address any feedback in code review.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Testing\n\nAt the oml folder, there is an application named \u003ca href=\"oml/Ultimate%20PDF%20Tests.oml\"\u003eUltimate PDF Tests\u003c/a\u003e that contains multiple examples and tests of the component. All the pull requests will be tested against the test application scenarios. Use this application to test your changes before sending the PR.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Acknowledgments\n\nProject base on OutSystems Forge component \u003ca href=\"https://www.outsystems.com/forge/component-overview/5641/ultimate-pdf\"\u003eUltimate PDF\u003c/a\u003e.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foutsystems%2Fultimatepdf-externallogic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foutsystems%2Fultimatepdf-externallogic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foutsystems%2Fultimatepdf-externallogic/lists"}