Coder Social home page Coder Social logo

numde / compass-numapp-frontend Goto Github PK

View Code? Open in Web Editor NEW
15.0 15.0 9.0 160.73 MB

The repository for the frontend component of the NUM-App

License: Apache License 2.0

JavaScript 98.38% Starlark 0.44% Java 0.45% C 0.02% Objective-C 0.44% Ruby 0.28%
javascript mobile-app react-native

compass-numapp-frontend's People

Contributors

alena456 avatar alenaschmickl avatar dependabot[bot] avatar golexprime avatar johannesoehm avatar lenzch avatar lgtm-com[bot] avatar mahvaezi avatar mbastian93 avatar medonja avatar renovate[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

compass-numapp-frontend's Issues

Current questionnaire is always marked as 'obsolete'

Describe the bug
Every time a 'user update' is triggered when there is already a questionnaire present, the user is informed that this one is obsolete, even though the new one is exactly the same as the current one.

To Reproduce
Steps to reproduce the behavior:

  1. Open app
  2. When questionnaire is available: repeatedly hit the 'refresh' button
  3. Each time user is informed, that the current questionnaire would be 'obsolete'

Expected behavior
An update should only happen, when the currently persisted questionnaire definitely differs from the one to be fetched from the backend.

Screenshots
-/-

Smartphone (please complete the following information):
any device

Additional context
-/-

Incorrect FHIR implementation of multiple-choice (checkbox) questions

Describe the bug
In FHIR questionnaires, questions that support more than one answer need to be marked with "repeats": true.
Currently, the differentiation between radio button questions vs. checkbox questions is done by using either the choice or open-choice type, but the latter is meant for a different use case:
Like with choice questions, for open-choice there is a fixed list of possible answer options, but additionally a free-text field is supposed to be provided. (That is what distinguishes it from choice questions)

Expected behavior
The backend does not send questionnaires with items of type open-choice, but instead with type choice and sends an additional property "repeats": true. The frontend distinguishes radio button questions (single-choice) vs. checkbox (multiple-choice) by looking at the repeats property. If it is absent or false, radio buttons are rendered for choice questions.

Additional context

https://www.hl7.org/fhir/codesystem-item-type.html#item-type-open-choice

https://www.hl7.org/fhir/questionnaire-definitions.html#Questionnaire.item.repeats

Support item.answerOption for item.type = string and item.type = integer

Is your feature request related to a problem? Please describe.
I'm not sure if this is only a feature request or if this rather qualifies as a bug. The issue is, that the FHIR specification for item.type = "choice" says:
Question with a Coding drawn from a list of possible answers (specified in either the answerOption property, or via the valueset referenced in the answerValueSet property) as an answer (valueCoding). (https://www.hl7.org/fhir/valueset-item-type.html),
which is also consistent with the mapping table outlined in https://www.hl7.org/fhir/questionnaire.html#question-types

At the same time, the documentation for the item.anwerOption element says:
One of the permitted answers for a "choice" or "open-choice" question. (https://www.hl7.org/fhir/questionnaire-definitions.html#Questionnaire.item.answerOption), with leads to the question, why item.answerOption.value[x] should be a union type at all.

A inquiry in the zulip-Chat answered by Llyod McKenzie clarified, that the answerOption-list is meant to be used with other types:
https://chat.fhir.org/#narrow/stream/179255-questionnaire/topic/type.3Dchoice.20and.20answerOption.2EvalueInteger.3F

Describe the solution you'd like
I would like, that the app checks for items of type string or integer, if there is a answerOption list. In that case, a list should be rendered rather than a radio list or a combobox than the text field.

Describe alternatives you've considered

  • The alternative would be also to drop support for Questionnaires with item.type = choice and answerOptions of type string or integer. However, to stay somewhat downwards compatible, I would'nt recommend that.
  • Another alternative would be to use this different behaviour as a compass-internal convention. However, this would be not good because other FHIR-Questionnaire-Tools might not be able to handle Questionnaires, which do not conform to the FHIR specification.

Multi-language support for questionnaires

The NUM-App mobile app should offer multi-language support for questionnaires. This implies that questionnaires can be retrieved and delivered in n languages. Moreover, texts in the app should be displayed in the same language or in a fallback language. The initial language is determined by the settings of the participant's mobile phone. The participant must have the option to change the language in the app at a later stage.

This issue is linked to the required change in the mobile backend.

The implementation should follow the specification given in the following sequence diagram:

Mehrsprachigkeit

Detect jailbbroken/rooted devices

Is your feature request related to a problem? Please describe.
Rooted/jailbroken devices should be recognized and usage thereof should be prevented.

Describe the solution you'd like
Make use of jail-monkey

Describe alternatives you've considered
-/-

Additional context
-/-

Slider value gets "forgotten" in UI

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Open the first group of the default questionnaire
  2. Navigate the questionnaire modal pages using the arrows until you see the slider
  3. Drag the slider in any direction but the middle.
  4. Click on the arrow in any direction or the ☑️-button.
  5. Navigate back, see that the value you just entered using the slider is lost. The slider is again in "middle position".

Expected behavior
The previously entered value is still set in the slider.

Screenshots
If applicable, add screenshots to help explain your problem.

Smartphone (please complete the following information):

  • Device: iPhone 11 (Simulator)
  • OS: iOS

Additional context
Add any other context about the problem here.

Input Validation and Correction is not working properly anymore

Describe the bug
The input validation of the questionnaire-modal does not work with type string anymore. This also prohibits the proper storage of a given answer. Furthermore the input correction also only works on types decimal and integer if the first entered character is indeed a number (nonetheless, the correct value is persisted).

To Reproduce
Steps to reproduce the behavior:

  1. Load the Generic Reference Questionnaire into the app.
  2. Open the "Fragegruppe 1" category.
  3. Enter someting into the input "Das ist eine Freitextabfrage".
  4. The button on the bottom does not turn green.
  5. Close the modal and open it again.
  6. The given answer will not reappear.
  7. Without closing the modal navigate to the question "Das ist eine Dezimalzahlenabfrage" and enter anything besides a number.
  8. If the entered value starts with anything but a number the input correction is not executed.

Expected behavior

  • The validation for type string should recognize an entered string.
  • An input for elements of type integer and/or decimal should prohibit invalid input.

Screenshots
Screenshot 2021-09-08 at 09 43 03
Screenshot 2021-09-08 at 09 43 47

Smartphone (please complete the following information):

  • Device: iOS Simulator
  • OS: iOS 12

Additional context

  • The input validation issue came up with a change in the file questionnaireModal.jsx
  • The input correction error seems to be the result of a change that occurred in how RN handles the value updates of input elements

Support more/all 'enableWhen'-operators

Is your feature request related to a problem? Please describe.
Currently only the 'enableWhen'-operator for equality is supported, which limits the design of the questionnaires.

Describe the solution you'd like
Add support for more (preferably all) operators.

Describe alternatives you've considered
-/-

Additional context
-/-

encode questionnaireID in rest service

When requesting a questionnaire via GET, the id should be encoded because if it is a URI it contains path separators (and possibly other special characters) and therefore causing invalid/wrong requests.

The clearAll method on the About-Screen is throwing an error

Describe the bug
When in DEV mode a button appears on the AboutScreen: logout and delete all local data.
It does exactly what the name suggests - but now it's also throwing an error.

To Reproduce
Steps to reproduce the behavior:

  1. Use the app in DEV mode
  2. Login and open the About screen
  3. Press logout and delete all local data
  4. Exception is thrown and the user is navigated to the Landing screen

Expected behavior
No exceptions thrown and the user is navigated to the Landing screen

Screenshots
Screenshot 2021-09-16 at 11 58 37

Smartphone (please complete the following information):

  • Device: iOS Simulator / iPhone 12
  • OS: iOS 14.5

Additional context
It's just the order of execution - logout should occur before the deletion of the local data.

Add a way to inform the user that a date has not been choosen on iOS

Is your feature request related to a problem? Please describe.
Currently, on iOS, a Date-Spinner is used, which is by default is set to the current date. However, this default date is not transfered into the internal application state. The only indication of this behaviour is the green color of the "Checkmark"-button on the bottom of the modal (but also the black "Checkmark"-button allows for switching the page, so he probably even won't understand its meaning) and the fact that the user cannot submit the questionnaire.

If the user clicks back into the questionnaire, he sees that there is a value entered in the date field, but the checkmark button is not green. If the date field is combined with other (maybe optional) questions in one page, it is even harder for him to figure out why the submission fails.

If the user wants to enter today's date, he must set another date and then switch back to todays date.

Describe the solution you'd like

  • A text field is drawn and empty by default. If the user clicks, a modal window is open to choose the date. Just like android behaviour.

Describe alternatives you've considered

  • The default date could be automatically transferred into the questionnaireItemMap. However, this would lead to unwanted behaviour if the information of the date field is not actively filled in and left empty on purpose.
  • A checkbox "I choose not to answer". Example: https://chat.fhir.org/#narrow/stream/179255-questionnaire

Implement certificate pinning

Is your feature request related to a problem? Please describe.
Implement certificate pinning to prevent usage of unauthorized/untrusted certificates.

Describe the solution you'd like
Make use of react-native-ssl-pinning.

Describe alternatives you've considered
-/-

Additional context
-/-

Support for questionnaire-item-control = "radio-button" oder "drop-down"

The Extension http://hl7.org/fhir/R4/extension-questionnaire-itemcontrol.html allows for choice-types the choosing between radio-buttons and drop-down menus. Currently, the app uses always radio-buttons if there is a

Even though it allows not for new use-cases, this is a common option in most EDC systems, as depending of the length of the questionnaire and the length of the list of choices, drop-down menus can be more clear.

Transform into template

Transform this project into a template, so that a new app based upon this project can be created by executing

npx react-native init MyNewProject --template [path-to-template]

where 'path-to-template' is the link to this repository

Release v0.1.1 crashing

It seems that the v0.1.1 release introduces a new problem, which makes the app crash on Android:
The provided demo APK crashes as well.

Caused by: java.lang.UnsupportedOperationException: Your application is configured to use RNGestureHandlerEnabledRootView which is no longer supported. You can see how to migrate to here: https://docs.swmansion.com/react-native-gesture-handler/docs/guides/migrating-off-rnghenabledroot
at com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView.(RNGestureHandlerEnabledRootView.kt:17)
at de.num.ukbumfragetool.android.MainActivity$1.createRootView(MainActivity.java:29)
at com.facebook.react.ReactActivityDelegate$1.createRootView(ReactActivityDelegate.java:82)
at com.facebook.react.ReactDelegate.loadApp(ReactDelegate.java:102)
at com.facebook.react.ReactActivityDelegate.loadApp(ReactActivityDelegate.java:91)
at com.facebook.react.ReactActivityDelegate.onCreate(ReactActivityDelegate.java:86)
at com.facebook.react.ReactActivity.onCreate(ReactActivity.java:46)
at de.num.ukbumfragetool.android.MainActivity.onCreate(MainActivity.java:37)
at android.app.Activity.performCreate(Activity.java:8207)
at android.app.Activity.performCreate(Activity.java:8191)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3808)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4011) 
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2325) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:246) 
at android.app.ActivityThread.main(ActivityThread.java:8633) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130) 

Questionnaire purpose field not shown in frontend app

It seems like that the frontend app does not anywhere show a Questionnaire's purpose received from the backend. This is a different behavior than that experienced in the web client, where the purpose is shown at the questionnaire's overview page. To me, this looks like a bug, is this actually intended to be like that?
I am refering to the purpose field as shown in the generic questionnaire sample: https://github.com/NUMde/compass-implementation-guide/blob/master/input/questionnaire-generic.json

Unterstützung für http://hl7.org/fhir/R4/extension-questionnaire-hidden.html

Mit dieser Extension ist es möglich, Elemente aus dem Questionnaire für den Nutzer zu verstecken.

Hintergrund: Dieses ist eine übliche Option in gängigen EDC-Systemen. Dies kann in einer Vielzahl von Szenarien nützlich sein:

  • Informationen, die nicht den Nutzer direkt gefragt werden, sondern anderswo im Code bereitgestellt werden (z.B. per Bluetooth-Verbindung über Wearables oder Meta-Informationen wie die benötigte Zeit zum Ausfüllen), können so im "eigentlichen" Questionnaire untergebracht werden.
  • Im Entwicklungsprozess des Formulares können verschiedene Varianten eines Formulares getestet werden
  • Abwärtskompatibiltät zu älteren Versionen des Fragebogens kann gewahrt werden, wenn Elemente entfernt werden.

Support child items for all questionnaire item types (except 'display')

Is your feature request related to a problem? Please describe.
Currently only questionnaire items of type 'group' can have child items. However according to the specification (rule 'que-1') only items of type 'display' explicitly cannot have child items. Hence all other types can have child items.

Describe the solution you'd like
Allow for all questionnaire items except 'display' items to have children. This is especially useful for conditional questions and their grouping.

Describe alternatives you've considered
Theoretically items can be grouped by grouping them in an item of type 'group'. However, such an item must have a title, causing duplications and/or a bad layout.

Additional context
-/-

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • chore(deps): update babel monorepo to v7.24.6 (@babel/core, @babel/eslint-parser, @babel/preset-env)
  • chore(deps): update dependency @testing-library/react-native to v12.5.1
  • chore(deps): update dependency eslint to v8.57.0
  • chore(deps): update dependency eslint-plugin-import to v2.29.1
  • chore(deps): update dependency eslint-plugin-jest to v27.9.0
  • chore(deps): update dependency eslint-plugin-jsx-a11y to v6.8.0
  • chore(deps): update dependency msw to v1.3.3
  • fix(deps): update @react-native-firebase to v18.9.0 (@react-native-firebase/app, @react-native-firebase/messaging)
  • fix(deps): update dependency @react-native-community/datetimepicker to v7.7.0
  • fix(deps): update dependency @react-native-community/slider to v4.5.2
  • fix(deps): update dependency @react-native-picker/picker to v2.7.6
  • fix(deps): update dependency react-native-gesture-handler to v2.16.2
  • fix(deps): update dependency react-native-localize to v3.1.0
  • fix(deps): update dependency react-native-screens to v3.31.1
  • fix(deps): update dependency react-native-vision-camera to v2.16.8
  • fix(deps): update dependency react-native-webview to v13.10.2
  • chore(deps): update dependency eslint to v9
  • chore(deps): update dependency eslint-config-prettier to v9
  • chore(deps): update dependency eslint-plugin-jest to v28
  • chore(deps): update dependency jsdom to v24
  • chore(deps): update dependency msw to v2
  • fix(deps): update @react-native-firebase to v20 (major) (@react-native-firebase/app, @react-native-firebase/messaging)
  • fix(deps): update dependency @react-native-community/datetimepicker to v8
  • fix(deps): update dependency @reduxjs/toolkit to v2
  • fix(deps): update dependency react-native-vision-camera to v4
  • fix(deps): update dependency react-redux to v9
  • fix(deps): update dependency redux-thunk to v3
  • 🔐 Create all rate-limited PRs at once 🔐

Edited/Blocked

These updates have been manually edited so Renovate will no longer make changes. To discard all commits and start over, click on a checkbox.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

npm
compass-numapp-template/package.json
  • @react-native-community/datetimepicker 7.4.1
  • @react-native-community/slider 4.4.3
  • @react-native-firebase/app 18.3.0
  • @react-native-firebase/messaging 18.3.0
  • @react-native-picker/picker 2.4.10
  • @react-navigation/native 6.1.7
  • @react-navigation/native-stack 6.9.13
  • @reduxjs/toolkit 1.9.5
  • babel-plugin-module-resolver 5.0.0
  • buffer 6.0.3
  • i18n-js 3.9.2
  • lodash.clonedeep 4.5.0
  • lodash.debounce 4.0.8
  • lodash.memoize 4.1.2
  • node-forge 1.3.1
  • prop-types 15.8.1
  • react 18.1.0
  • react-native 0.70.6
  • react-native-elements 3.4.3
  • react-native-encrypted-storage 4.0.3
  • react-native-gesture-handler 2.12.0
  • react-native-localize 3.0.2
  • react-native-modal 13.0.1
  • react-native-reanimated 2.17.0
  • react-native-safe-area-context 4.7.1
  • react-native-screens 3.25.0
  • react-native-splash-screen 3.3.0
  • react-native-url-polyfill 2.0.0
  • react-native-vector-icons 10.0.0
  • react-native-vision-camera 2.15.4
  • react-native-webview 13.3.0
  • react-redux 8.1.1
  • redux-persist 6.0.0
  • redux-thunk 2.4.2
  • vision-camera-code-scanner 0.2.0
  • @babel/core 7.23.2
  • @babel/eslint-parser ^7.19.1
  • @babel/preset-env 7.23.2
  • @react-native-community/eslint-config 3.2.0
  • @testing-library/react-native 12.1.3
  • babel-jest 29.7.0
  • eslint 8.45.0
  • eslint-config-airbnb 19.0.4
  • eslint-config-prettier 8.10.0
  • eslint-formatter-github-annotations 0.1.0
  • eslint-import-resolver-babel-module 5.3.2
  • eslint-plugin-eslint-comments 3.2.0
  • eslint-plugin-flowtype 8.0.3
  • eslint-plugin-import 2.28.1
  • eslint-plugin-jest 27.2.3
  • eslint-plugin-jsx-a11y 6.7.1
  • eslint-plugin-prettier 5.0.0
  • jest 29.7.0
  • jest-transform-stub 2.0.0
  • jsdom 22.1.0
  • metro-react-native-babel-preset 0.77.0
  • msw 1.2.3
  • patch-package 8.0.0
  • react-test-renderer 18.1.0
  • node >=18.0.0
  • npm >=8.0.0
package.json

  • Check this box to trigger a request for Renovate to run again on this repository

Exception is thrown when trying multiple login-attempts

Describe the bug
An exception is thrown when the app tries to remove subjectID from the encrypted storage that does not exist. This occurs when a user tries to repeatedly login (for example with invalid credentials) and also to navigate back to the landing screen between tries.

To Reproduce
Steps to reproduce the behavior:

  1. Go to 'Login Screen'
  2. Login with wrong credentials
  3. Navigate back to "Landing Screen"
  4. See error

Expected behavior
No thrown exception.

Screenshots
Screenshot 2021-09-20 at 12 43 20
Screenshot 2021-09-20 at 12 43 24

Smartphone (please complete the following information):

  • iPhone Simulator
  • OS: iOS 14.5

Don't request a certificate with each user update

Currently, with every user update, a 'new' certificate for the encryption of the questionnaire response is sent back to the user although it rarely - if ever - changes, therefore causing some overhead. So we might as well store it locally and only re-request a new certificate, if the current one is not valid anymore. This would obviously require the backend to be modified as well.

No error-handling in case of authentication-mishaps

Describe the bug
There is no informing of the user that something went wrong after an error during authentication.

To Reproduce
Steps to reproduce the behavior:

  1. Try to login without valid credentials or a working backend.

Expected behavior
Some kind of information about what just happened would be appreciated.

Smartphone (please complete the following information):

  • Device: iPhone 12 Simulator
  • OS: 14.5

Improve testing

Improve testing by restricting unit tests and maybe use cavy for integration tests instead of exploiting the currently used testing framework.

Also extend coverage, i.e. add more test cases.

ESLint & Prettier

Add

to this project, to enforce consistent and uniform code style as well as reduce and prevent errors by enforcing best-practices

Please check if the default date is always set on iOS

Describe the bug
When using the DateTimePicker on iOS, the initial value is the current date. But, if the user doesn't change it, the value is not set in the questionnaireItemMap.

To Reproduce
Steps to reproduce the behavior:

  1. Go to the default questionnaire, first page
  2. Click on always on next, fill in empty values, but do not touch the DateTimePicker
  3. Try to submit the questionnaire, it is not possible because the date is not set in the questionnaireItemMap (but the item is required), even though it looks to the user like it is set.

Expected behavior
The default date of the slider is incorporated into the normal state.

Screenshots
If applicable, add screenshots to help explain your problem.

Smartphone (please complete the following information):

  • iOS Emulator

Additional context
An open question is, how the android behaviour should be. By looking at the source code, it looks to me like Android supports also empty dates. There should be a unique behaviour on both platforms, preferably one where it is possible to omit dates.

Change list of questionnaire categories to to dropdown

Is your feature request related to a problem? Please describe.
Currently, there is no way to directly jump to a question at a specific index. Hence, when a category consists of a large number of question on must click through all of them to get to the last ones, which can be quite annoying.

Describe the solution you'd like
Change the List of categories on the survey screen to dropdown elements so that when expanded, the questions of this category are listed and when tapping those, the modal is opened with that question

Describe alternatives you've considered
-/-

Additional context
-/-

enableWhen state should be inherited to childs of item

Describe the bug
The FHIR specification states that "When an item is disabled, all of its descendants are disabled, regardless of what their own enableWhen logic might evaluate to." (https://www.hl7.org/fhir/questionnaire-definitions.html#Questionnaire.item.enableWhen)

However, it seems that the child items are ignoring this expression and are shown eben if the parent group is disabled.

To Reproduce
Steps to reproduce the behavior:

  1. Load the GECCO Reference Questionnaire into the app
  2. Open the "Anamnese" Formular
  3. Set "Chronische Lungenerkrankung" to "No"
  4. Questions for every possible lung disease are shown nevertheless on the next page

Expected behavior
Next page is skipped since all questions are disabled by parent group's enableWhen attribute.

Smartphone (please complete the following information):

  • iOS 11, Emulator

exportAndUploadQuestionnaireResponse() cannot be triggered from the CheckIn-Screen

Describe the bug
The button to send out the questionnaire response is not working, at all.

To Reproduce
Steps to reproduce the behavior:

  1. Try to send out a completed questionnaire response from the CheckIn-Screen. Or just try to hit the deactivated button.

Expected behavior
Something, anything happens.

Screenshots
Of what? 🤔

Smartphone (please complete the following information):

  • Device: iPhone 12 Simulator
  • OS: iOS 14.5

Additional context
It's just the missing exportAndUploadQuestionnaireResponse declaration in the deconstruction of the props of the CheckInScreen-Component.

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.