Giter Site home page Giter Site logo

incodehq / incode-platform Goto Github PK

View Code? Open in Web Editor NEW
8.0 8.0 9.0 112.32 MB

Combines incode.org modules and isisaddons.org into a single set of modules.

Home Page: http://platform.incode.org

License: Apache License 2.0

Java 18.48% Shell 0.09% HTML 0.60% CSS 0.05% JavaScript 64.32% Clean 0.06% Gherkin 0.01% Groovy 0.05% Dockerfile 0.01% Rich Text Format 15.96% TSQL 0.38%

incode-platform's People

Contributors

danhaywood avatar dependabot[bot] avatar jcvanderwal avatar johandoornenbal avatar marcusvanbergen avatar martin-g avatar mwhesse avatar niv0 avatar oscarbou avatar ppirus avatar scascarini avatar stevecam62 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

incode-platform's Issues

lib-integtestsupport: add in a LoggingRule to help debugging

    public static Logger LOG = LoggerFactory.getLogger(SimpleModuleIntegTestAbstract.class);

    public static class LoggingRule implements MethodRule {

        @Override
        public Statement apply(
                final Statement statement, final FrameworkMethod frameworkMethod, final Object o) {
            return new Statement() {

                public void evaluate() throws Throwable {
                    log("start");
                    try {
                        statement.evaluate();
                    } catch (final Throwable ex) {
                        log("exception");
                        throw ex;
                    } finally {
                        log("done");
                    }
                }

                void log(final String suffix) {
                    LOG.info(String.format(
                            "%s#%s: %s",
                            frameworkMethod.getDeclaringClass().getName(),
                            frameworkMethod.getMethod().getName(),
                            suffix));
                }

            };
        }
    }

    @Rule
    public LoggingRule loggingRule = new LoggingRule();

dom-commchannel: column "placeId" has maximum length of 255

Some place ids have a length greater than 255 characters

javax.jdo.JDOFatalUserException
Attempt to store value "......" in column "placeId" that has maximum length of 255. Please correct your data!
org.datanucleus.api.jdo.NucleusJDOHelper#getJDOExceptionForNucleusException(NucleusJDOHelper.java:616)
org.datanucleus.api.jdo.JDOPersistenceManager#jdoMakePersistent(JDOPersistenceManager.java:725)
org.datanucleus.api.jdo.JDOPersistenceManager#makePersistent(JDOPersistenceManager.java:745)
org.apache.isis.objectstore.jdo.datanucleus.persistence.commands.DataNucleusCreateObjectCommand#execute(DataNucleusCreateObjectCommand.java:54)
org.apache.isis.core.runtime.system.persistence.PersistenceSession#executeCommands(PersistenceSession.java:1253)
org.apache.isis.core.runtime.system.persistence.PersistenceSession#execute(PersistenceSession.java:1247)

dom-security: rework module to use objectType instead of class name

select * from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME LIKE '%class%' or COLUMN_NAME like 'fully%' or COLUMN_NAME like '%fq%' or COLUMN_NAME like '%domainType%'
order by COLUMN_NAME, TABLE_NAME
which gives us:

incodeDocuments Applicability attachmentAdvisorClassName
dbo Link className
incodeDocuments Applicability domainClassName
incodeClassification Applicability domainType
isissecurity ApplicationPermission featureFqn
dbo FixedAssetRegistrationType fullyQualifiedClassName
incodeClassification Category fullyQualifiedName
incodeDocuments RenderingStrategy rendererClassName
incodeDocuments Applicability rendererModelFactoryClassName

spi-security: Compatibility with Oracle 11

from isisaddons-legacy/isis-module-security#34

Default names of tables and foreign keys are incompatible with Oracle 11 - since some of them are longer then 30 characters.

This constraint can be solved by externalizing the package.jdo file and adaptin it, but in the e.g. ApplicationPermission class the index name is simply too long:

@javax.jdo.annotations.Uniques({@javax.jdo.annotations.Unique(name = "ApplicationPermission_role_feature_rule_UNQ", members = {"role", "featureType", "featureFqn", "rule"})})

In total there are 7 indexes with too long names.

Incode Platform build fails at the Integration tests

This is the test report --


Test set: domainapp.modules.simple.integtests.tests.SimpleObjectMenu_IntegTest$Create

Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.294 sec - in domainapp.modules.simple.integtests.tests.SimpleObjectMenu_IntegTest$Create

Test set: domainapp.modules.simple.integtests.tests.SimpleObjectMenu_IntegTest$ListAll

Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.021 sec <<< FAILURE! - in domainapp.modules.simple.integtests.tests.SimpleObjectMenu_IntegTest$ListAll
happyCase(domainapp.modules.simple.integtests.tests.SimpleObjectMenu_IntegTest$ListAll) Time elapsed: 0.007 sec <<< ERROR!
java.lang.NoSuchMethodError: org.apache.isis.applib.services.repository.RepositoryService.persist(Ljava/lang/Object;)V
at domainapp.modules.simple.integtests.tests.SimpleObjectMenu_IntegTest$ListAll.happyCase(SimpleObjectMenu_IntegTest.java:43)


Test set: domainapp.modules.simple.integtests.tests.SimpleObject_IntegTest$DataNucleusId

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 4.782 sec <<< FAILURE! - in domainapp.modules.simple.integtests.tests.SimpleObject_IntegTest$DataNucleusId
should_be_populated(domainapp.modules.simple.integtests.tests.SimpleObject_IntegTest$DataNucleusId) Time elapsed: 0.034 sec <<< ERROR!
java.lang.NoSuchMethodError: org.apache.isis.applib.services.repository.RepositoryService.persist(Ljava/lang/Object;)V


Test set: domainapp.modules.simple.integtests.tests.SimpleObject_IntegTest$DataNucleusVersionTimestamp

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0 sec <<< FAILURE! - in domainapp.modules.simple.integtests.tests.SimpleObject_IntegTest$DataNucleusVersionTimestamp
should_be_populated(domainapp.modules.simple.integtests.tests.SimpleObject_IntegTest$DataNucleusVersionTimestamp) Time elapsed: 0 sec <<< ERROR!
java.lang.NoSuchMethodError: org.apache.isis.applib.services.repository.RepositoryService.persist(Ljava/lang/Object;)V


Test set: domainapp.modules.simple.integtests.tests.SimpleObject_IntegTest$Name

Tests run: 2, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 0 sec <<< FAILURE! - in domainapp.modules.simple.integtests.tests.SimpleObject_IntegTest$Name
accessible(domainapp.modules.simple.integtests.tests.SimpleObject_IntegTest$Name) Time elapsed: 0 sec <<< ERROR!
java.lang.NoSuchMethodError: org.apache.isis.applib.services.repository.RepositoryService.persist(Ljava/lang/Object;)V

not_editable(domainapp.modules.simple.integtests.tests.SimpleObject_IntegTest$Name) Time elapsed: 0 sec <<< ERROR!
java.lang.NoSuchMethodError: org.apache.isis.applib.services.repository.RepositoryService.persist(Ljava/lang/Object;)V


Test set: domainapp.modules.simple.integtests.tests.SimpleObject_IntegTest$Title

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0 sec <<< FAILURE! - in domainapp.modules.simple.integtests.tests.SimpleObject_IntegTest$Title
interpolatesName(domainapp.modules.simple.integtests.tests.SimpleObject_IntegTest$Title) Time elapsed: 0 sec <<< ERROR!
"tests.txt" 53L, 4999C

spi-security: Use SudoService.Spi to propagate user/role permissions to an effective user

from isisaddons-legacy/isis-module-security#48

As introduced in 1.13.2

I tried to implement this at the generic Shiro security mechanism (within Isis core), but realized that actually it needs to be at a deeper level, ie in this module.

The code I sketched out before abandoning was:

@DomainService(nature = NatureOfService.DOMAIN)
public class SudoServiceSpi implements SudoService.Spi {

    @Override
    public void runAs(final String username, final List<String> roles) {
        try {
            final Subject subject = SecurityUtils.getSubject();
            if (subject == null) {
                return;
            }
            // can't set runAs if has no current principals
            if(!hasPrincipals(subject)) {
                return;
            }
            final SimplePrincipalCollection principals = new SimplePrincipalCollection();
            principals.add(new RunAsPrincipal(username, roles), "sudoRealm");
            subject.runAs(principals);
        } catch(UnavailableSecurityManagerException ex) {
            return;
        }
    }

    private boolean hasPrincipals(final Subject subject) {
        return !CollectionUtils.isEmpty(subject.getPrincipals());
    }

    @Override
    public void releaseRunAs() {
        try {
            final Subject subject = SecurityUtils.getSubject();
            if(subject == null) {
                return;
            }
            // can't set runAs if has no current principals
            if(!hasPrincipals(subject) || !subject.isRunAs()) {
                return;
            }
            subject.releaseRunAs();
        } catch (UnavailableSecurityManagerException ex) {
            return;
        }
    }
}

and also:

public class RunAsPrincipal implements AuthorizationInfo {

    private final String username;
    private final List<String> roles;

    public RunAsPrincipal(final String username, final List<String> roles) {
        this.username = username;
        this.roles = roles;
    }

    @Override
    public Collection<String> getRoles() {
        return roles;
    }

    @Override
    public Collection<String> getStringPermissions() {
        return Collections.emptyList();
    }

    @Override
    public Collection<Permission> getObjectPermissions() {
        return Collections.emptyList();
    }
}

Certainly RunAsPrincipal won't be needed; instead use the PrincipalForApplicationUser that already exists.

Also, will need to decide what to do if the specified user doesn't exist in the user; perhaps fall back on the above generic code (meaning no permissions, of course).

dom-classifications: rework module to use objectType rather than class name.

for the "applicableToDomainType"
select * from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME LIKE '%class%' or COLUMN_NAME like 'fully%' or COLUMN_NAME like '%fq%' or COLUMN_NAME like '%domainType%'
order by COLUMN_NAME, TABLE_NAME

which gives us:

incodeDocuments Applicability attachmentAdvisorClassName
dbo Link className
incodeDocuments Applicability domainClassName
incodeClassification Applicability domainType
isissecurity ApplicationPermission featureFqn
dbo FixedAssetRegistrationType fullyQualifiedClassName
incodeClassification Category fullyQualifiedName
incodeDocuments RenderingStrategy rendererClassName
incodeDocuments Applicability rendererModelFactoryClassName

wkt-excel: Download in multiple formats (eg raw entities, and discovered DTOs) with a selector

from isisaddons-legacy/isis-wicket-excel#4

introduce this into Isis applib:

public interface Mapper<S,T> {

```
Class<? extends S> getSourceClass();
Class<? extends T> getTargetClass();

@Programmatic
T map(S s);
```

}

Then search for domain classes that implement:

@DomainService(nature=DOMAIN)
public CountryToDto implements Mapper<Country, CountryDto> {
   public CountryDto map(Country c) { ... }
}

@DomainService(nature=DOMAIN)
public CountryToRowHandler implements Mapper<Country, CountryRowHandler> {
   public CountryRowHandler map(Country c) { ... }
}

and provide a drop-down selector to choose how to export (as Country, as CountryDto, as CountryRowHandler etc).

```
```

lib-excel: Referenced entities should be looked up also through the Auto-Complete facet

from isisaddons-legacy/isis-module-excel#7

oscar:

Current implementation exports and imports properties referencing other entities by writing:

  1. on the Excel cell's value the title of the entity.
  2. on the Excel cell's comment, the internal Id. of the referenced object.

As those internal ids are can be automatically generated by the datastore, the wouldn't be known when defining an initial set of entities to be imported (for example, imagine a TodoItem that references a "parent " TodoItem; all them are going to be initially imported from Excel).

The proposed solution complements current logic by trying to find the corresponding entity by means of the AutoComplete facet (if defined for the Entity). That's the more generic way on Apache Isis to search for a concrete entity using a simple String.

Update isis docs with this hint originally in the pdf.js demo app (now removed)

here's the text that has been removed

Demo App: Highlighting Current

As a by-the-by, the demo app has one further "trick up its sleeve".
If you run the app you'll notice that the currently selected DemoObject is highlighted in the left-hand table of the HomePageViewModel.

This is accomplished by having the view model collaborate with a subscribing domain service that configures a CSS class.

We start by ensuring that the DemoObject emits an event for its CSS class:

.DemoObject.java

@DomainObjectLayout(
        ...
        cssClassUiEvent = DemoObject.CssClassUiEvent.class
)
public class DemoObject ... {

    public static class CssClassUiEvent
            extends org.apache.isis.applib.services.eventbus.CssClassUiEvent<DemoObject> {}
    ...
}

Next, we define the domain service to act as the subscriber.
Since it will be interact

.HomePageViewModel.java

public class HomePageViewModel ... {

    @DomainService(nature = NatureOfService.DOMAIN)
    public static class CssHighlighter extends AbstractSubscriber {

        @EventHandler
        @Subscribe
        public void on(DemoObject.CssClassUiEvent ev) {
            if(getContext() == null) {
                return;
            }
            if(ev.getSource() == getContext().getSelected()) {      // <1>
                ev.setCssClass("selected");
            }
        }

        private HomePageViewModel getContext() {                    // <2>
            return (HomePageViewModel) scratchpad.get("context");
        }
        void setContext(final HomePageViewModel homePageViewModel) {
            scratchpad.put("context", homePageViewModel);
        }

        @Inject
        Scratchpad scratchpad;                                      // <3>
    }
}

<1> If the domain object is the currently selected then set the CSS class
<2> Provide methods to set and get the current HomePageViewModel (acting as the context)
<3> Store the context using the Scratchpad domain service (request-scoped so thread-safe).

The HomePageViewModel is responsible for setting itself as the context for the domain service:

.HomePageViewModel.java

public class HomePageViewModel ... {
    ...
    public TranslatableString title() {
        cssHighlighter.setContext(this);    // <1>
        ...
    }
    ...
    @javax.inject.Inject
    CssHighlighter cssHighlighter;
}

<1> set the context on the domain service

Finally we just need some CSS, in the application.css file:

.application.css

.selected {
    font-style: italic;
    font-weight: bolder;
}

spi-security: Different datastore for datatables, also LDAP implementation

from isisaddons-legacy/isis-module-security#37

Kambiz wrote:

Hi,

we are trying to use the security module which would be a perfect fit
for our needs if it had a fully LDAP based implementation.

To make things even more difficult, we are building up an infrastructure
where several domains with separate databases exist.

Problem 1: the JDO annotations of the domain objects in the module
obviously don't use the DataNucleus extension to specify a different
data store than the default one.

This leads to users/roles being created in the 'default data store' of
the respective service and we are not easily able to redirect the
security related persistence towards a central 'security database'.

Problem 2: a fully LDAP based implementation is what the customer needs

If an LDAP backend is present in a company, then one would expect to
handle all of the authentication/authorisation issues on that side
without the need to have an additional database which might get out of
sync with the single source of truth which should be LDAP.

We have found out that DataNucleus even has an LDAP data store
implementation.

Would it be possible to implement a fully LDAP based backend for the
security module? We would be willing to invest some effort, if you could
guide us on how to tackle the problem.

Thanks

dom-commchannel: Geocode lookup Integration tests fail

Failed integration tests:

CommunicationChannelOwner_addPostalAddress_IntegTest$ActionImplementationIntegrationTest.can_create_postal_address_and_also_look_up_geocode:131
Expecting:
"51.7525548,-1.2501191"
to match pattern:
"51.75256[\d][\d],-1.25011[\d][\d]"
PostalAddress_lookupGeocode_IntegTest$ActionImplementationIntegrationTest.will_always_lookup_as_best_as_possible:88
Expecting:
"51.7525548,-1.2501191"
to match pattern:
"51.75256[\d][\d],-1.25011[\d][\d]"
PostalAddress_update_IntegTest$ActionImplementationIntegrationTest.when_lookup_geocode_or_does_not_loookup:87
Expecting:
"51.7525548,-1.2501191"
to match pattern:
"51.75256[\d][\d],-1.25011[\d][\d]"

lib-excel: Cannot attempt to run the same (subclass of) ExcelFixture2 more than once.

from isisaddons-legacy/isis-module-excel#20

Pretty sure this is because ExcelFixture2 (and maybe ExcelFixture)'s value semantics is broken.

If if try to run the same subclass of ExcelFixture2 more than once, then this code in FixtureScript.java

    //region > shouldExecute
    private boolean shouldExecute(final FixtureScript fixtureScript) {

        final boolean previouslyExecuted = this.previouslyExecuted.contains(fixtureScript);
        if(!previouslyExecuted) {
            this.previouslyExecuted.add(fixtureScript);
        }

will fail, because of the "contains" call is gonna call getBytes() on the candidate fixture script which will in turn return null because the fixture script hasn't been run (we're trying to figure out at this stage whether to run the fixture script).

dom-document: rework module to use objectType instead of class name

for the "applicableToDomainType
select * from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME LIKE '%class%' or COLUMN_NAME like 'fully%' or COLUMN_NAME like '%fq%' or COLUMN_NAME like '%domainType%'
order by COLUMN_NAME, TABLE_NAME

which gives us:

incodeDocuments Applicability attachmentAdvisorClassName
dbo Link className
incodeDocuments Applicability domainClassName
incodeClassification Applicability domainType
isissecurity ApplicationPermission featureFqn
dbo FixedAssetRegistrationType fullyQualifiedClassName
incodeClassification Category fullyQualifiedName
incodeDocuments RenderingStrategy rendererClassName
incodeDocuments Applicability rendererModelFactoryClassName

spi-security: Support multiple realms

from isisaddons-legacy/isis-module-security#29

I would like to use a shiro possibility to have multiple realms:

1.) to have in INI realm administrator uses
2.) thru this addon create additional users and authenticate them with their passwords

I've tried to adapt the AuthenticationStrategyForIsisModuleSecurityRealm, but it fails when tries to authentificate the user from addon, but failed. 

Here the adapted Strategy, I've varied the subclassing of strategies, actually I would need "AtLeastOneSuccessfulStrategy" but failed

<pre>
package security;

import java.util.Collection;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.pam.AllSuccessfulStrategy;
import org.apache.shiro.realm.Realm;

/**
 * Created by niv on 12.04.2016.
 */
public class AuthenticationStrategyForIsisModuleSecurityRealm2 extends AllSuccessfulStrategy {
    public AuthenticationStrategyForIsisModuleSecurityRealm2() {
    }

    @Override
    public AuthenticationInfo beforeAllAttempts(Collection<? extends Realm> realms, AuthenticationToken token) throws AuthenticationException {
        AuthenticationInfo auth = null;
        for (Realm realm : realms) {
            try {
                auth = realm.getAuthenticationInfo(token);
                if (auth != null)
                    return auth;

            } catch (IncorrectCredentialsException e) {
                System.out.println(e.getMessage());
                // catching when single realm throws authentification exception
            }
        }
        throw new AuthenticationException("no provided realms could't authenticate user, realm count:" + realms.size());
    }
}
</pre>


Here my shiro.ini:

<pre>
_[main]
isisModuleSecurityRealm=org.isisaddons.module.security.shiro.IsisModuleSecurityRealm
authenticationStrategy=security.AuthenticationStrategyForIsisModuleSecurityRealm2
securityManager.authenticator.authenticationStrategy =$authenticationStrategy
securityManager.realms =  $iniRealm,$isisModuleSecurityRealm

[users]
# user = password, role1, role2, role3, ...
sven = pass, admin_role, isis-module-security-admin
dick = pass, user_role, self-install_role
bob  = pass, user_role, self-install_role
joe  = pass, user_role, self-install_role
guest = guest, user_role


[roles]
user_role =   *:SimpleObjects:*:*,\
              *:SimpleObject:*:*
self-install_role = *:DomainAppFixtureService:*:*
admin_role = *
_
</pre>

ext-quartz: add in with AbstractIsisQuartzJob

public class AbstractIsisQuartzJob implements Job {

    public static enum ConcurrentInstancesPolicy {
        SINGLE_INSTANCE_ONLY,
        MULTIPLE_INSTANCES
    }
    
    private final AbstractIsisSessionTemplate isisRunnable;

    private final ConcurrentInstancesPolicy concurrentInstancesPolicy;
    private boolean executing;

    public AbstractIsisQuartzJob(AbstractIsisSessionTemplate isisRunnable) {
        this(isisRunnable, ConcurrentInstancesPolicy.SINGLE_INSTANCE_ONLY);
    }
    public AbstractIsisQuartzJob(
            AbstractIsisSessionTemplate isisRunnable, 
            ConcurrentInstancesPolicy concurrentInstancesPolicy) {
        this.isisRunnable = isisRunnable;
        this.concurrentInstancesPolicy = concurrentInstancesPolicy;
    }

    /**
     * Sets up an {@link IsisSession} then delegates to the 
     * {@link #doExecute(JobExecutionContext) hook}. 
     */
    public void execute(final JobExecutionContext context) throws JobExecutionException {
        final AuthenticationSession authSession = newAuthSession(context);
        try {
            if(executing &&
               concurrentInstancesPolicy == ConcurrentInstancesPolicy.SINGLE_INSTANCE_ONLY) {
                return;
            }
            executing = true;

            isisRunnable.execute(authSession, context);
        } finally {
            executing = false;
        }
    }

    AuthenticationSession newAuthSession(JobExecutionContext context) {
        String user = getKey(context, SchedulerConstants.USER_KEY);
        String rolesStr = getKey(context, SchedulerConstants.ROLES_KEY);
        String[] roles = Iterables.toArray(
                Splitter.on(",").split(rolesStr), String.class);
        return new SimpleSession(user, roles);
    }

    String getKey(JobExecutionContext context, String key) {
        return context.getMergedJobDataMap().getString(key);
    }
}

dom-note: [Feature request] allow threaded comments to be added to notes

per Vladimir on [email protected] (http://markmail.org/message/e7tacn3lxuej4hfj)

In a world of collaboration systems there could be an interesting extension
to your incode-module-note feature, the capability not only to add the
notes to an entity, but also to add infinite comments to that note (in
other words to add the comment threads to the entity). In combination with
text search capability (idea #1) I thinks we could build really great
features.

Text search is https://issues.apache.org/jira/browse/ISIS-383

wkt-wickedcharts: NPE when invalid data is provided

from isisaddons-legacy/isis-wicket-wickedcharts#2

With the current Java Math demo data in the KitchenSink application trying to show a summarychart leads to the following exception:

Caused by: java.lang.NullPointerException
    at java.math.BigDecimal.compareTo(BigDecimal.java:2554)
    at java.math.BigDecimal.min(BigDecimal.java:2665)
    at org.isisaddons.wicket.wickedcharts.cpt.ui.summarychart.CollectionContentsAsSummaryChart.minOf(CollectionContentsAsSummaryChart.java:163)
    at org.isisaddons.wicket.wickedcharts.cpt.ui.summarychart.CollectionContentsAsSummaryChart.createChartValue(CollectionContentsAsSummaryChart.java:119)
    at org.isisaddons.wicket.wickedcharts.cpt.ui.summarychart.CollectionContentsAsSummaryChart.buildGui(CollectionContentsAsSummaryChart.java:101)
    at org.isisaddons.wicket.wickedcharts.cpt.ui.summarychart.CollectionContentsAsSummaryChart.onModelChanged(CollectionContentsAsSummaryChart.java:168)

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.