GithubHelp home page GithubHelp logo

rxindi's Introduction

Rxindi

Rxindi is an Adobe InDesign Extension that allows for powerful one-click data merge, document composition and dynamic processing of reusable InDesign templates based on content coming from a variety of formats.

  1. Get the Rxindi InDesign Extension on Adobe Marketplace
  2. Open its interface via Window > Extensions > Rxindi
  3. Create a template InDesign document with special placeholder statements inside text frames for any variable data or automation that needs to occur
  4. Select a Data Source file: Excel (XLSX), CSV, XML or JSON
  5. Process the document

Rxindi is simple to use, very lightweight and portable. The statements used for the processing instructions are all plain text and stored within you regular InDesign documents. No special plugins are needed to write them or to open/edit documents that contain them.

Capabilities

  • Use XML, CSV, JSON or XLSX as input data
  • OUTPUT arbitrary content from the selected data file (using XPath) to:
    • Text
    • Images
    • QR Codes
  • Conditional content (IF-ELSE)
  • Repeat content (LOOP)
  • Generate table rows (ROWREPEAT)
  • Create and reuse content COMPONENTs: Define a snippet once and use it many times with different data
  • Automatically execute custom SCRIPTs on inline text or frames
  • Perform special ACTIONs such as:
    • Dynamically Hide/Show frames
    • Apply Object/Paragraph/Character/Table/Cell styles
    • Dynamically choose a State for Multi-state objects

Statement syntax

Rxindi Statements consist of a single character (e.g. =, ?) followed by arguments and can be used in inline text anywhere in the document. To separate them from regular content in text they are placed in a ${...} placeholder, e.g. ${=FirstName}.

Multiple statements are separated by placing them in separate placeholders: ${=FirstName} ${=LastName} or by placing them in the same placeholder separated with a semicolon or a newline: ${=FirstName;=LastName}. Anything outside placeholders is treated as story content, but a powerful feature of Rxindi is that it does participate in processing, e.g. when using conditionals (IF-ELSE), repeating content (LOOP) or Components.

The following is an example with various statements an example that outputs "FirstName LastName" or just "LastName"

${?HasFirstName}${=FirstName}${:}  ${=' ';   .;   =LastName}
  ^IF             ^OUTPUT      ^ELSE ^OUTPUT ^END ^OUTPUT

In this example, HasFirstName, FirstName and LastName are XPath queries (the path to an element) for the data source document that is to be used

More info

rxindi's People

Contributors

rxcle avatar

Stargazers

 avatar Bryan Onel avatar  avatar  avatar Ed Clews avatar

Watchers

 avatar  avatar  avatar

Forkers

gitter-badger

rxindi's Issues

[1.3.1] Add Action types for changing table/row/cell styles

The ACTION statement has action types for setting Object, Character and Paragraph styles. Which, if used in combination with IF allows for dynamic styling of a document, based on input data. To allow for dynamic styling of InDesign tables in a similar fashion, consider adding new ACTION types for changing the current style of a Table, Row and Cell.

Arguments for

  • More dynamic styling options
  • Allowing dynamic styling of tables will enable some great on-the fly formatting options
  • Should be relatively low effort to add, with little perceived risk of breaking existing functionality and low impact on testing

Arguments against

  • Unknown

[1.3.1] ODS Support

Propose to add ODS (OpenDocument Spreadsheet) support as an input data source format.

Arguments for

  • Embrace the biggest (offline) and open-source spreadsheet format as an alternative for Excel files

Arguments against

  • Yet another format to support, test and document
  • OpenOffice/LibreOffice already supports import/export of Excel files, so there is not a direct urgency for this

Only 1 Image

Hello,

if I use this code, then unfortunately only 1 picture comes up, unfortunately it doesn't copy the picture frame. Can I adjust something there?

${*Sheet/Row}
Image Frame
${=/Root/Sheet/Row[7]/Picture,ProfilePic}
${=/Root/Sheet/Row[7]/Name}
${.}

My Output is:

Image
Name
Name
Name
Name
...

I want
Image
Name
Image
Name
...

Can you help? :)

Thank you

[1.3.1] Processing a document with unknown script succeeds without error

When using the SCRIPT statement in a document and the script name doesn't refer to an existing script, the processing of the document succeeds without giving any error or warning. This is not correct as it gives the false impression to the user that everything was processed, while the script call (which may contain vital functionality for a document) seems completely ignored.

[1.1.0] Add a way to reference frames from spawned components and iterations uniquely

Consider an image frame called "ImageFrame" in a Component/Loop template. When there is a statement in the same template that reference the ImageFrame then upon multiple instantiations, the particular frame of that instance cannot currently be referenced. Reason is that upon instantiation of a template, all frames retain their original name, making it so that multiple frames with the same name exist - in which case only the first found frame is used as found target for the reference.

This is against expectation and the most typical use case for users.

Example:

${*/Root/Sheet/Row}
<<IMG Name=ImageFrame>>
${=Name}
${=Picture,ImageFrame}
${.}

Here, on every iteration a new image frame called "ImageFrame" is spawned, the Output statement that targets the frame will always find the very first one though.

Reported by: End-User
Occurs in: v1.0.0-1.1.0
Occurs on: All Platforms, All InDesign versions
Workaround exists: Yes (partial) - Create custom script that renames frame after every template instantiation

[1.3.1] LOOP/ROWREPEAT path resulting in NaN skips ELSE

If the result from the path is a number type of value NaN then the ELSE block (if defined) is incorrectly skipped.

Repro:

${*number(NaN)}NOK${:}OK${.}

Expected result is "OK" but actual result is nothing.

Low impact due to the rarity of having to deal with NaN in typical use cases, and if needs be there is a workaround by adding an extra IF (which does handle NaN correctly)

[1.3.1] Events

Proposal to add functionality to allow subscribing to certain events that may get triggered during processing of a document. The handler of the event would then be a typical Rxindi block. Two examples of events would/could be useful: "processStart" and "processFinish". Many more events could be thought of, specifically around data-missing and error-handling cases.

Arguments for

  • Makes it much easier to execute certain statements at exact points
  • Enabler for other future usecases which require to always run before and after everything else.
  • Relatively low development effort

Arguments against

  • Will (very likely) require extension of the statements set.
    • Could potentially be mitigated if this is integrated with an explicit BLOCK / CONTEXT statement. See #15

[1.3.1] Context selection

Statements in Rxindi all act on a single data context, which is a pointer to some element in the data source. While this works well enough for now, as an enabler for potential new features, (e.g. multiple data sources, component arguments), some way to access data from a different context than the default could be added to the Rxindi path syntax.

Note that this proposal does not deal with how new contexts come to be, just on how to select data from different contexts, assuming they exist.

Some early ideas: Give contexts a name and wherever a path is used, allow it to be prefixed with the context on which to act. If no context name is given, the default context is used. Such a context prefix system might also be an enabler for #24.

Arguments for

  • Enabler for various features dealing with data
  • If the syntax is determined, should be relatively low effort

Arguments against

  • Without supporting features actually needing multiple contexts clearly defined, the business case for this is flimsy
  • Somewhat risky, because backwards compatibility on existing, non-prefixed paths in templates should not break.

[1.0.2] Problème Rwindi sur mac

Bonjour
Je viens d'acheter l'extension Rxindi pour indesign 2022. et cela ne fonctionne pas.Il affiche "validating..."
et rien de se passe.
idem avec "processing..." et rien.
Je viens de voir qu'il fonctionne sur mon pc. Sauf que je ne travaille pas sur PC.
Capture d’écran 2022-04-07 à 11 18 13

[1.3.1] Component contents is not deleted when document is processed

When I create a component that solely consists of a table, the component itself is not removed when Rxindi is run. This is consistent with what happens when you select a table and press backspace, which leads to the table contents being deleted but the table remaining.

When using:
image

it Leads to:
image

[1.3.1] Check existence of styles for ACTION in validation pass

When referring to an Object/Paragraph/Character-Style in the ACTION types ostyle, pstyle and cstyle, the existence of the styles is only checked during the processing phase. The result of this is that referring to an unknown style will cause the validation to pass, but will cause a processing error - leaving the document in an unfinished processing state.

When investigating if this check can be moved to the validation pass, also take along state for MSO's - though this might be tougher to implement as states are defined per MSO and not globally like styles.

[1.3.1] Documentation refresh

The Rxindi manual was originally created during the early beta stages and only has seen minimal updates since. Some of the topics might come across as confusing while others are not explained in enough details.

[1.3.1] ScriptArgs.args may be undefined

The documentation reads that the scriptArgs.args property in scripts called with the SCRIPT statement contains an array of additional arguments passed to the script. It seems however that in certain cases the property returns undefined instead.

Needs further investigation.

[1.3.1] Load into XML Structure does not clear previous result

When using the "Load into XML Structure" command via the Rxindi menu then the structure of the data can get visually "merged" with the result from a previous invocation. The expected behavior is that the command will always and only show the structure of the most recent loaded data.

Manual workaround: Right-click the root level in the structure view and choose "Delete" before calling Rxindi's "Load into XML structure".

[1.3.1] Improve processing error behavior

If an error occurs during processing then the template document is left in a half-processed state, with processing helping elements still in-place. For users this is not helpful at all.

Two options in case of error:

  1. Revert the document back to the saved state automatically
  2. Keep the document as-is but clean up the processing helpers

Option 1 seems the more logical choice, but this will also block the user in case the document is "good enough" to continue with, even if there was an error during processing - in which case option 2 is more useful. Also, option 2 still allows a manual revert by the user, but if Rxindi always does an auto-revert then anything that was already processed is gone. Ideally this would be a user-configurable option, but right now Rxindi doesn't have options yet.

[1.3.1] XPath cannot contain a a semicolon or closing curly brace

Statements that take an XPath query as an argument cannot contain a semicolon ; or closing curly brace }. The \ character is supposed to serve as an escape character, but this doesn't work correctly.

This impacts the following statements:

  • OUTPUT
  • IF
  • LOOP
  • ROWREPEAT

The consequence is as follows:

  • Closing burly brace and semicolon cannot appear in literal strings, e.q. string('\;') is not supported right now.

This issue is present since Rxindi v1.0.0.
The severity is currently assessed to be mid to low, as typical paths for selecting data from the data file are not impacted by this.

Note: Comma's are supported but need to be explicitly escaped using \, e.g. concat('a'\,'b') - same is expected for } and ;

[1.3.0] LOOP over element with single result sets incorrect context for block

When using a LOOP statement over a collection in the data source, the child context for the LOOP body should be set to the current element in the iteration. This works correctly in case there are multiple elements, however, if the expression results in a single item then the context is not changed.

This seems like a regression from the behavior in v1.2.0

Workaround is available: Surround the LOOP with an IF that checks for a single item and handle that case explicitly (not nice, but workable)

End of paragraph character not parsed properly

Whenever I use \r instead of \n in strings contained in a JSON file, I expect that character to be parsed as a 'new paragraph' rather than a 'newline'.

It however seems that \r and \n are parsed the exact same way and both lead to a new line.

[1.3.1] Processing stuck on non-XML files (HELP REQUEST)

Several report have come in that Rxindi is only working correctly when using XML files. When using Excel, JSON or CSV it gets stuck on on Processing Data Source.

Internally this has not been reproduced yet (on Windows or Mac).

Help request on anyone who has this issue to provide as much detail/repro steps and if possible example templates & data.

[1.3.1] Compatibility handling

Rxindi currently has no explicit means of handling compatibility with templates created for older or newer versions of Rxindi. In a multi-user environment, all users must be on the same version and the template must be made for that version.

Because there are some proposals to making a few breaking changes in the core feature set, this can become problematic - especially because there is no (easy) way for a user to pick and choose a specific (e.g. older) version of Rxindi to use for a certain template/datafile.

It might be necessary going forward to have at least some enforced backward compatibility either through global toggles in the Rxindi UI or (/and) explicitly marking templates as being compatible for a certain version of Rxindi.

This needs to be worked out further before it can be planned...

[1.3.1] Inline targets

Targets for Rxindi statements (e.g. OUTPUT) always have to point to a frame. Propose to introduce the concept of inline-targets, which would allow for outputting towards any part of a story from within a different part of the story or a completely different story/textframe. Basically you're dropping a named "anchor" somewhere in text and target that from statements somewhere else.

What such an anchor would look like is yet to be worked out.

  • In its simplest form it would be a dedicated new statement type
    • but this kind of defeats the point of cleaning up statements from the actual user content.
  • Alternatively an existing InDesign text-level element could be used, e.g. XML Tags, Hyperlinks or Notes.
    • This does introduce an entirely new concept for the user to learn and manual/tutorials to explain.

Arguments for

  • This could potentially clean up a lot of the template by moving more complex statements elsewhere and just putting a target marker at the place where content should be output
  • Seems like a true logical counterpart to targeting image frames; The current targeting to textframes, which always and only appends seems limited.

Arguments against

  • Completely new concept to learn, explain, test
  • Potential implementation difficulties because things like anchors placed inside other Rxindi statements need to be handled (think especially about repeating content LOOP and disappearing content with IF)

[1.3.1] Allow raw transformation of CSV, XLSX (and maybe JSON)

When specifying a CSV, XLSX or JSON file Rxindi performs an opinionated transformation into an XML structure. While the chosen transformation leads to "logical" and "easy to use" paths to data for many users, there are drawbacks when the input structure is not in a predefined format. For example, for the mapping in Excel to work, the first row must contain headers.

Propose to add an option that (besides the existing transformation) allows a "raw" transformation - which is unopinionated on the input structure, making everything represent-able in the target XML in a consistent way. The paths for this would be more cumbersome, but for power-users this should not be an issue.

Arguments for

  • Truly enable any structure as input and not be limited to expecting e.g. headers in spreadsheets
  • Have a singular, very consistent mapping
  • Even if column names are supplied, anything that cannot be represented as an XML Element name (e.g. spaces, special chars) causes mangled element names representing said columns

Arguments against

  • As this cannot be auto-detected, the requested mapping must be indicated by the user. This adds an additional step and more complexity for the user.
  • Where to keep/store this setting? It is kind of tied to both the template and input file.

[1.3.1] Add action type to clear frame content

After the change in v1.3.0 to always append to rather than replace the content of a frame with a targeted OUTPUT - there is no longer an easy way to have some content in a frame in the template and to replace it during processing. Propose to a add a new ACTION type clear to clear any content in a given frame.

The target frame to clear may have Rxindi statements. Propose to let the action type check for this and give an error to disallow clearing said frame. Both alternatives to this (clearing everything including statements or selectively clearing only the content but not the statements) are hard to implement correctly and likely lead to behavior that is undesirable for almost every use case. Performing the aforementioned check also prevents the user from clearing the frame containing the executing clear action itself.

[1.3.1] Component arguments

Proposal to add functionality to allow passing extra arguments on PLACE that Components can use. Right now the only input a component receives is the context.

Needs investigation how to best tackle this.

In its most basic form this would work much the same on the caller side as arguments to SCRIPT. But then how do statements in the COMPONENT declaration consume them?

A more advanced form could tie into #28, where any path can select the data context where to take data from. The input arguments from PLACE could then be a new data context, which paths inside the COMPONENT declaration use paths on.

Arguments for

  • More flexible components
  • Enabler for receiving data from events

Arguments against

  • Complex to implement; ties into many other concepts

[1.3.1] XPath everywhere

Propose to investigate if functionality could be added to allow an XPath statement for any Rxindi statement argument. For instance, get the name of a target frame or style via XPath from data. Some additional annotation would be needed for this, because now such arguments are always treated as literal (and are not valid XPath).

Arguments for

  • Powerful (and arguably "neat") function to allow any data to come from XPath

Arguments against

  • Use-cases for this might be quite niche; Not worth the development, test and maintenance effort
  • For most typical use (and backwards compatibility) existing name-like parameters should remain as-is, so some special syntax is needed to indicate an XPath; Yet another concept to document
  • May lead to quite confusing errors and templates that only work with very specific data

[1.4.0] Unexpected behavior of table styling ACTIONs in ROWREPEAT

Using the table styling actions tcstyle and tcrstyle conditionally in the template row for a ROWREPEAT may also apply the style in other (following) rows, even if the condition there is false.

Example, assuming Items/Item returns 3 or more elements:

Column 1 ...
${-Items/Item}${?@rxc-index=2}${!tcstyle:STYLEA} ...

Expected behavior is that Cell Style STYLEA is only applied to the first column of the second data row (header excluded), not to any other row (or column).

Column 1 ...
- -
STYLEA -
- -
- -

Actual behavior in Rxindi 1.4.0 is that the style is applied to the first column of the second data row, but also to the first column of any row following it, the condition is ignored.

Column 1 ...
- -
STYLEA -
STYLEA -
STYLEA -

[1.3.1] OUTPUT with URL targeting QR code sometimes fails

Seen in several scenarios:

  • Create a (text) QR Code
  • Name the frame
  • Fill the initial text with some dummy value
  • Create an OUTPUT with the QR Code frame as target and selecting a URL from input data
  • Generate
  • Sometimes fails
  • Mange the URL (e.g. put something in front of it)
  • Now works

[1.3.1] Provide more context for processing errors

Validation phase errors typically provide detailed information on the source of the error. This is currently not the case for errors encountered during processing. In some cases the error message is sparse and the user is left to guess to the actual source of the error in the document.

Investigate what can be done to improve this.

[1.3.1] Batch processing

Proposal to add functionality to batch process a template with multiple/many data files of the same structure.

A lot of details need to be fleshed out on the key value points here. From the face of it this doesn't seem very useful unless there is also some built-in functionality to save and/or export processed documents automatically, which opens a whole can of worms (or peaches, depending on how you look at it) on additional related functionality.

Arguments for

  • This is a no-brainer, the whole point of Rxindi is speeding up document generation through automation - having it just being able to process a single file at a time seems like there is something lacking.

Arguments against

  • Development cost
  • Danger of scope creep - there is almost no end to the set of functions that could be added to this, in order to be flexible for every possible usage scenario

[1.3.1] ROWREPEAT doesn't work when n=1

Problem

It seems that ROWREPEAT only works if the number of elements of any path is larger than one.

This is not desirable behavior, as there are many scenarios in which it is unknown ahead of time whether an array will consist of just one element or more.

In my particular case this happens when generating reports that have a contacts table. Some reports have one contact, others have multiple.

Background

This is my setup:

image

N > 1 functions properly

With the following XML

<tenant>
        <name>Acme Inc.</name>
        <people>
            <name>Test Person 1</name>
            <position>CEO</position>
        </people>
        <people>
            <name>Test Person 2</name>
            <position>CTO</position>
        </people>
</tenant>

Everything works as expected:

image

N = 1 Fails

The expected functionality fails however if the following XML is used:

<tenant>
        <name>Acme Inc.</name>
        <people>
            <name>Test Person 1</name>
            <position>CEO</position>
        </people>
</tenant>

Leading to the following output:

image

[1.3.1] Function Components

Proposal to add a new type of Component: Function Components.
Components of this type are not instantiated on Place but instead (only) execute Rxindi statements - using the caller context as default context.

Options for declaring them:

  • Special prefix for name
  • New argument on COMPONENT statement, declaring a type (current Component type would still be default if not specified)

Arguments for

  • For writing a reusable set of statements where you're not interested in content instantiation from the component declaration, functional components would be much faster to execute.
  • Could be an enabler for events (i.e. they could be triggered by something other than an explicit Place).
  • Relatively low effort to implement and low(-ish) risk

Arguments against

  • Other than being able to speed up processing a bit and being an enabler, it in itself doesn't bring any new functionality for end-users.

Feature request - ability to use Rxindi through Applescript

For my specific use case, using AppleScript, I want to be able to:

  1. Open InDesign
  2. Open my template to populate data into
  3. Call Rxindi through a mechanism like doScript, providing the json file to use as an argument.
  4. export the pdf

Context: It is possible to have jsx scripts executed through the following
app.doScript(runRxindi, ScriptLanguage.JAVASCRIPT, ['jsonFileToLoad'])
but this only works for scripts, not extensions.

Would you have any idea how to achieve this? My workflow relies heavily on being able to automatically have Rxindi executed rather than having to click GUI buttons.

[1.3.1] Remove support for statements in frame script labels

Rxindi statements can currently be placed in either stories (text frames) or in script labels on any frame type. Propose to remove support for the later case and support only statements in text-frames.

History

Support for statements in script labels was added in a very early (pre v1.0) stage, before targeting for OUTPUT etc was implemented and several solutions on how to handle outputting to image frames in particular were being explored.

Arguments for removal

  • Its usage is rather awkward and quite different from the "standard" way, because it requires the frame itself to have a name starting with a $ (for performance reasons), while statements themselves have to be specified without placeholders.
  • Some statement types (by definition) will only work if used in a text-frame, e.g. COMPONENT, ROWREPEAT. While others like LOOP will work but do not make much sense outside the context of a text-frame.
  • It is better to have a clear single way on doing this, as this makes Rxindi more consistent and focused of a solution.
  • There are very few (if any) cases that can be solved with this that cannot be solved with statements in a (different) text-frame that target the frame needing output.
  • The concept of script labels is rather foreign to most InDesign users.
  • Editing script labels in InDesign is rather error prone - it is not very obvious when changes in the editor for this are applied.
  • Mistakes in statements in the scripting label are hard for Rxindi to list and reference (while for statements in text frames, Rxindi can point to the exact location).
  • Statements in script labels always and only work on the global (root) data context. This is even true if the statements are on a script label of an inline/anchored frame that itself is in a story. By them not having any context it usage scenarios become even more limited. (Note that, in theory it would be possible to provide context in specific anchoring scenarios, but this would require significant development effort).
  • Keeping this (assumed obscure) functionality intact takes up testing resources and complicates further feature development.

Arguments against removal

  • This may actively be used in customer templates. Removal would break this.
    • Options: deprecate first before removal; add backwards compatibility mode; just accept breaking change and offer clear guidance on an alternate approach
  • Maybe there are (as yet unknown internally) cases that can really only be solved with this, which just don't work with statements in text-frames.
    • Options: In this case it might actually be good to get to the bottom of this, to better understand what is still missing in main statement writing scenario.

[1.3.1] Introduce new statement to change the context explicitly

When referencing more complex data often long and complex repeated paths are needed. Propose to add a solution that allows for shorter paths by adding a new block-type statement type that explicitly changes the data context for child statements (and does nothing else).

Arguments for

  • Simpler, shorter paths
  • Relatively easy to add, little risk as context changes is already implemented in statements like LOOP, ROWREPEAT and PLACE

Arguments against

  • Yet another statement type to add to the Quick reference guide, manual and tutorials
  • The data context is a topic that is not really well understood by many users, so this would be scoped more towards "power-users"

[1.3.0] Multiple ROWREPEAT statements in table give a validation error

ROWREPEAT statement validation might incorrectly report than only a single ROWREPEAT is allowed per row even if the row only contains a single ROWREPEAT statement, but its containing table contains more than one ROWREPEAT.

Workaround: Currently only a single ROWREPEAT per table can be used (contrary to what is mentioned in the documentation) due to this bug - no (known) workaround is available at the moment.

[1.3.1] Feature request - Undo script run with single undo.

Background

I am currently in the process of converting pretty lengthy documents from my crappy own engine to Rxindi. Every time I convert elements to Rxindi I want to do a quick test run to check whether everything is working as expected.

When I run Rxindi and things don't look right, I have to hold ctrl+z for a very long time to get to the last normal 'draft' state I was in.

Due to the fact that files need to be saved for Rxindi to run, I need to constantly create clones of my files to be able to go back to where I left off.

It would be amazing if there was the option to undo all consequences of a Rxindi run through a single ctrl+z. In my own (crappy) engine this was accomplished through app.doScript(main, ScriptLanguage.javascript, [], UndoModes.ENTIRE_SCRIPT, "Replace Variables");

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.