sapuseven / betteruntis Goto Github PK
View Code? Open in Web Editor NEWAn alternative mobile client for the Untis timetable system.
License: GNU General Public License v3.0
An alternative mobile client for the Untis timetable system.
License: GNU General Public License v3.0
It would be great if this project had the Fastlane file structure for its F-Droid store listing. This would enable you to edit the title, description and screenshots of your app without having to open a merge request every time.
To make a pull request I would need up to date screenshots and a description because the description on F-Droid and the one on the Play Store are not the same.
In the Info section should be some menu to view class services like "Klassensprecher", "Tafeldienst" and "Ordnungsdienst"
Description
4 missing strings for translation
<string-array name="preference_schoolcolors"> <item>For regular lessons</item> <item>For lessons with tests</item> <item>For irregular lessons</item> <item>For cancelled lessons</item> </string-array>
Any updates from weblate.org?
Additional information
After reinstalling BetterUntis, this time downloaded from sapuseven.com/app/BetterUntis/ instead of build myself, it manages to crash every time when logging it.
The Demo school worked just fine for me
logcat
10-06 21:06:51.449 8328 8328 E AndroidRuntime: Process: com.sapuseven.untis.debug, PID: 8328
10-06 21:06:51.449 8328 8328 E AndroidRuntime: at com.sapuseven.untis.models.UntisUserData$$serializer.deserialize(Unknown Source:149)
10-06 21:06:51.449 8328 8328 E AndroidRuntime: at com.sapuseven.untis.models.UntisUserData$$serializer.deserialize(UntisUserData.kt:10)
10-06 21:06:51.449 8328 8328 E AndroidRuntime: at com.sapuseven.untis.models.untis.response.UserDataResponse$$serializer.deserialize(Unknown Source:142)
10-06 21:06:51.449 8328 8328 E AndroidRuntime: at com.sapuseven.untis.models.untis.response.UserDataResponse$$serializer.deserialize(UserDataResponse.kt:7)
10-06 21:06:51.449 8328 8328 E AndroidRuntime: at com.sapuseven.untis.activities.LoginDataInputActivity.acquireUserData(LoginDataInputActivity.kt:275)
10-06 21:06:51.449 8328 8328 E AndroidRuntime: at com.sapuseven.untis.activities.LoginDataInputActivity$acquireUserData$1.invokeSuspend(Unknown Source:13)
10-06 21:06:51.457 1447 1907 W ActivityManager: Force finishing activity com.sapuseven.untis.debug/com.sapuseven.untis.activities.LoginDataInputActivity
Please add a button to the top right of the screen (in the AppBar, on the personal timetable), which when clicked scrolls to today.
The button should show a calender icon. Maybe also show the current date in it.
I know you can click on the calendar icon and than click on today. But we got free screenspace there and it adds a neat shortcut.
I got this idea from the Orignal Untis app.
The app crashes by clicking on info center with this stacktrace:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.sapuseven.untis.debug, PID: 9920
kotlinx.serialization.json.JsonUnknownKeyException: Strict JSON encountered unknown key: jsonrpc
You can disable strict mode to skip unknown keys
at kotlinx.serialization.json.internal.StreamingJsonInput.decodeElementIndex(StreamingJsonInput.kt:96)
at com.sapuseven.untis.models.untis.response.ExamResponse$$serializer.deserialize(Unknown Source:18)
at com.sapuseven.untis.models.untis.response.ExamResponse$$serializer.deserialize(ExamResponse.kt:7)
at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:33)
at kotlinx.serialization.json.internal.StreamingJsonInput.decodeSerializableValue(StreamingJsonInput.kt:29)
at kotlinx.serialization.CoreKt.decode(Core.kt:79)
at kotlinx.serialization.json.Json.parse(Json.kt:148)
at com.sapuseven.untis.activities.InfoCenterActivity.loadExams(InfoCenterActivity.kt:217)
at com.sapuseven.untis.activities.InfoCenterActivity$loadExams$1.invokeSuspend(Unknown Source:12)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Nice to see a new BetterUntis written in Kotlin.
Since this new version does not contain any closed source libs you can publish it on F-Droid. I would really like to see it there.
The lessons from my school go from the first to the 16th lesson. My lessons are only from the second to the 9th lesson. It would be great if I can display only this time slot.
If e.g. a room has been changed, I would like to see this directly in the timetable view (e.g. 111 222) just like OpenUntis and the official Untis apps do. Currently, I have to click on the details popup to see what actually has changed.
Thanks for BetterUntis, it is great!
For privacy reasons I use and provide a proxy for the untis site and API: https://github.com/Perflyst/OpenUntis/blob/master/docs/setup-proxy.md
"mobile.webuntis.com" was not used in the legacy app but is used in this one. Please add some "advanced user" option or similar to be able to change this URL.
Could you use weblate.org for the translation?
It is free (gratis) for Free Software projects, uses the GPLv3 and is easier to contribute for translators.
Currently, if a course is cancelled only for a different class, Better Untis will show this in the 'irregular' color scheme although nothing actually changes for me. If I select the 'use school colors' scheme, the course will correctly show up in the normal color...update, just to clarify. I am talking about courses in which multiple classes are supposed to participate, like a Big Band or a school assembly.
Description
App crashes after selecting class. This is how I made it crash;
Edit:
Just experienced the same type crash when selecting room also. Another Norwegian school has the exact same issue; ID 1416900
Extracted from image above:
kotlinx.serialization.json.JsonParsingException:
Invalid JSON at 391: Expected '[, kind:
kotlinx.serialization.StructureKind$LIST@d4c9465'
at
kotlinx.serialization.json.internal.StreamingJsonlnput
begin Structure(Streaming Jsonl put.kt:116)
at
kotlinx.serialization.internal.AbstractCollection
Serializer.patch(Collection Serializers.kt:41)
at
kotlinx.serialization.internal.AbstractCollectionSeriali
zer.deserialize(Collection Serializers.kt:61)
at
kotlinx.serialization.json.internal.Polymorphic.deco
de Serializable Value Polymorphic(Polymorphic.kt:33)
at
kotlinx.serialization.json.internal.Streaming Jsonlnput
.decodeSerializableValue(Streaming Jsonl put.kt:29)
at
kotlinx.serialization.ElementValueDecoder.decodeSer
ializableElement(ElementWise.kt:142)
at
com.sapuseven.untis.models.untis.timetable PeriodT
ext$$serializer.deserialize(Unknown Source:101)
at
com.sapuseven.untis.models.untis.timetable.PeriodT
ext$$serializer.deserialize(PeriodText.kt:6)
at
kotlinx.serialization.json.internal.Polymorphic.deco
de Serializable Value Polymorphic(Polymorphic.kt:33)
at
kotlinx.serialization.json.internal.Streaming Jsonlnput
decodeSerializableValue(Streaming Json input.kt:29)
at
kotlinx.serialization.ElementValueDecoder.decodeSer
ializableElement(ElementWise.kt:142)
at
com.sap seven.units.models.untis.timetable. Period
Serializer.deserialize(Unknown Source:243)
at
com.sap seven.units.models.untis.timetable. Period
Serializer deserialize(Period kt:7)
Additional information
Unknown JSON object "attachments" encountered, value: []
Description
App crashes after choosing which school to use.
Actual behavior
I am not sure how to reproduce it, as the app seems to work fine for other users. After it's "finished" loading it either crashes with a brief error message or goes back to the main launch activity. I tried to capture the crash message. It's attached below.
Expected behavior
After the app finishes loading I would expect it to go to the timetables for that particular school.
Additional information
Tested with the 3.0.0-DEBUG+11.60 apk
10-09 15:18:14.116 6140 6140 E BetterUntis: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.sapuseven.untis.debug/com.sapuseven.untis.activities.MainActivity}: java.lang.IllegalArgumentException: No enum constant com.sapuseven.untis.helpers.timetable.TimetableDatabaseInterface.Type.com.sapuseven.untis.activities.MainActivity@d0001d8
10-09 15:18:14.116 6140 6140 E BetterUntis: at android.app.ActivityThread.performLaunchActivity(Unknown Source:591)
10-09 15:18:14.116 6140 6140 E BetterUntis: at android.app.ActivityThread.handleLaunchActivity(Unknown Source:36)
10-09 15:18:14.116 6140 6140 E BetterUntis: at android.app.servertransaction.LaunchActivityItem.execute(Unknown Source:57)
10-09 15:18:14.116 6140 6140 E BetterUntis: at android.app.servertransaction.TransactionExecutor.executeCallbacks(Unknown Source:99)
10-09 15:18:14.116 6140 6140 E BetterUntis: at android.app.servertransaction.TransactionExecutor.execute(Unknown Source:34)
10-09 15:18:14.116 6140 6140 E BetterUntis: at android.app.ActivityThread$H.handleMessage(Unknown Source:36)
10-09 15:18:14.116 6140 6140 E BetterUntis: at android.os.Handler.dispatchMessage(Unknown Source:21)
10-09 15:18:14.116 6140 6140 E BetterUntis: at android.os.Looper.loop(Unknown Source:208)
10-09 15:18:14.116 6140 6140 E BetterUntis: at android.app.ActivityThread.main(Unknown Source:107)
10-09 15:18:14.116 6140 6140 E BetterUntis: at java.lang.reflect.Method.invoke(Native Method)
10-09 15:18:14.116 6140 6140 E BetterUntis: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(Unknown Source:11)
10-09 15:18:14.116 6140 6140 E BetterUntis: at com.android.internal.os.ZygoteInit.main(Unknown Source:274)
10-09 15:18:14.116 6140 6140 E BetterUntis: Caused by: java.lang.IllegalArgumentException: No enum constant com.sapuseven.untis.helpers.timetable.TimetableDatabaseInterface.Type.com.sapuseven.untis.activities.MainActivity@d0001d8
10-09 15:18:14.116 6140 6140 E BetterUntis: at java.lang.Enum.valueOf(Enum.java:258)
10-09 15:18:14.116 6140 6140 E BetterUntis: at com.sapuseven.untis.helpers.timetable.TimetableDatabaseInterface$Type.valueOf(Unknown Source:2)
10-09 15:18:14.116 6140 6140 E BetterUntis: at com.sapuseven.untis.activities.MainActivity.showPersonalTimetable(MainActivity.kt:158)
10-09 15:18:14.116 6140 6140 E BetterUntis: at com.sapuseven.untis.activities.MainActivity.onCreate(MainActivity.kt:126)
10-09 15:18:14.116 6140 6140 E BetterUntis: at android.app.Activity.performCreate(Unknown Source:16)
10-09 15:18:14.116 6140 6140 E BetterUntis: at android.app.Activity.performCreate(Unknown Source:1)
10-09 15:18:14.116 6140 6140 E BetterUntis: at android.app.Instrumentation.callActivityOnCreate(Unknown Source:3)
10-09 15:18:14.116 6140 6140 E BetterUntis: at android.app.ActivityThread.performLaunchActivity(Unknown Source:368)
10-09 15:18:14.116 6140 6140 E BetterUntis: ... 11 more
10-09 15:18:30.980 6181 6181 E BetterUntis: Application crashed!
The app crashes while loading the timetable with internet connection.
If there is no internet connection I get an error like "mobile.webuntis.com" not found. Why does it even connect to mobile.webuntis.com?
BetterUntis is built from latest develop branch commit.
09-21 08:44:40.685 6971 6971 D TimetableLoaderDebug: target TimetableLoaderTarget(startDate=2019-09-21, endDate=2019-09-21, id=9213, type=STUDENT) (requestId 0): network request success, returning
09-21 08:44:40.687 6971 6971 D TimetableLoaderDebug: target TimetableLoaderTarget(startDate=2019-09-21, endDate=2019-09-21, id=9213, type=STUDENT) (requestId 0): saving to cache: STUDENT-9213-2019-09-21-2019-09-21
09-21 08:44:40.766 6971 6971 D TimetableLoaderDebug: target TimetableLoaderTarget(startDate=2019-09-15, endDate=2019-09-21, id=9213, type=STUDENT) (requestId 0): network request success, returning
09-21 08:44:40.793 6971 6971 D MainActivityDebug: addData received 21 items from 2019-09-15 until 2019-09-21
09-21 08:44:40.793 6971 6985 I art : Do full code cache collection, code=108KB, data=122KB
09-21 08:44:40.794 6971 6985 I art : Starting a blocking GC JitCodeCache
09-21 08:44:40.794 6971 6985 I art : After code cache collection, code=80KB, data=62KB
09-21 08:44:40.824 6971 6971 E AndroidRuntime: FATAL EXCEPTION: main
09-21 08:44:40.824 6971 6971 E AndroidRuntime: Process: com.sapuseven.untis.debug, PID: 6971
09-21 08:44:40.824 6971 6971 E AndroidRuntime: java.lang.ArrayIndexOutOfBoundsException: length=10; index=10
09-21 08:44:40.824 6971 6971 E AndroidRuntime: at com.sapuseven.untis.activities.MainActivity.mergeItems(MainActivity.kt:461)
09-21 08:44:40.824 6971 6971 E AndroidRuntime: at com.sapuseven.untis.activities.MainActivity.prepareItems(MainActivity.kt:426)
09-21 08:44:40.824 6971 6971 E AndroidRuntime: at com.sapuseven.untis.activities.MainActivity.addData(MainActivity.kt:687)
09-21 08:44:40.824 6971 6971 E AndroidRuntime: at com.sapuseven.untis.helpers.timetable.TimetableLoader.loadFromServer(TimetableLoader.kt:98)
09-21 08:44:40.824 6971 6971 E AndroidRuntime: at com.sapuseven.untis.helpers.timetable.TimetableLoader$loadFromServer$1.invokeSuspend(TimetableLoader.kt)
09-21 08:44:40.824 6971 6971 E AndroidRuntime: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
09-21 08:44:40.824 6971 6971 E AndroidRuntime: at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
09-21 08:44:40.824 6971 6971 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:751)
09-21 08:44:40.824 6971 6971 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95)
09-21 08:44:40.824 6971 6971 E AndroidRuntime: at android.os.Looper.loop(Looper.java:154)
09-21 08:44:40.824 6971 6971 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6186)
09-21 08:44:40.824 6971 6971 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
09-21 08:44:40.824 6971 6971 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
09-21 08:44:40.824 6971 6971 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
09-21 08:44:40.828 5066 5256 W ActivityManager: Force finishing activity com.sapuseven.untis.debug/com.sapuseven.untis.activities.MainActivity
09-21 08:44:40.835 5066 7031 W DropBoxManagerService: Dropping: data_app_crash (1277 > 0 bytes)
Description
The app shows an error message saying "No right for timetable".
Actual behavior
Sign in and try to show the timetable
Expected behavior
The timetable is correctly shown.
Request ID: 6
Error code: -8509
Error message: no right for timetable
Additional information (please replace)
It would be nice if BetterUntis would enable the do not disturb mode on lesson begin and disable it on lesson end, like OpenUntis.
Being able to see Homework like in the proprietary Untis app would be neat
For some schools it makes sense to be able to configure the displayed week length, for example to hide Saturdays if the school week ends at Friday.
The reason is probably that we got double lessons at our school. The first lessons is from 08:10 to 08:55 and the second one is from 08:55 to 09:40. I think the problem is that BetterUntis tries to unmute and mute the phone at the same time 08:55. This can result in a muted or unmuted phone because of inaccuracy of the timed broadcast. A simple solution is to check whether a difference between an end and a begin of a lesson is.
Description
For me only lessons 1 to 5 are showing. What it looks Like:
How it should be:
Actual behavior
Deleted all files and Reinstalled the app many Times, nothing Changed. I Think the Error comes Up because my school has to many Lessons at the Same time showing.
Expected behavior
A clear and concise description of what you expected to happen.
Add screenshots here to describe the problem.
Please include screenshots of the original Untis Mobile app if applicable.
Add a detailed stack trace / crash log here if applicable.
Additional information (please replace)
i was the Guy who requested the feature to only Show one day at the time.
If we got teacher substitutions on our school, the lesson is purple with the colors of the school and the normal lessons are orange. With not using the colors provided by the school, all lessons with and without substitution have the same color. It would be nice if this substitutions would be detected as irregular. Maybe we can use the provided color for this
If a proxy server is configured the "Show advanced settings" should be toggled by default (e.g. on edits)
Description
When I enable automute and notifications, I just get the notification before the first lesson, not the ones in between lessons. My best guess would be that AlarmManager drops the scheduled notification when the unmute is scheduled, since "If there is already an alarm scheduled for the same IntentSender, that previous alarm will first be canceled." (from the reference on AlarmManager)
Describe the solution you'd like
It would be nice if there was an option to see the current day on your watch.
Cancelled lessons have no color assigned by the school, so you should still be able to set a color for them if the school color scheme is used (i.e. the option to do so shouldn't be disabled)
BetterUntis 3.2.1 from Fdroid here on an Android 7.1.2.
I have set BetterUntis to only show "1" day of the week, ie today. (Note: The bug is gone if I select 2 days already.). When I swiped today (a Thursday) to the previous day, the schedule of Monday shows up. If I swipe once more, the very same Monday shows up. A third swipe will also show the very same Monday, a 4th swipe will then show Friday of last week.
The behavior is the same for the previous week then. (Mon-Wed all show the Monday schedule). If I swipe to the right, ie to tomorrow Friday, the correct day is shown.
So swiping days is like this:
Monday Jan 6 -> Monday Jan 6 -> Monday Jan 6 -> Thu Jan 9 -> Fri Jan 10 -> Mon Jan 13 -> Mon Jan 13 -> Mon Jan 13 -> Thu Jan 16 -> Fri Jan 17 -> ...
I hope you get the behavior I described, happy to clarify or provide a screencast is necessary.
Steps to reproduce:
-> You get back to the main view instead to the settings menu
Description
Now everything is splitted
logs-1583357588910.zip
logs-1583342047681.zip
Here are two logs from different Times.
Additional information
Description
The same day is displayed three times when swiping through the days.
No crash occured
Additional information
Description
BetterUntis instantly crashes when I try to open it. Because of the crash, I can't see any error message. But a friend sees a JSON parsing error
I could try add a more detailed log later, if needed
Additional information
Splitted lessons are somehow displayed wrong.
If the teacher got switched, it is not displayed at all in the app.
Since on my screenshots are teacher names etc I rather dont post the images here - I sent them to you via matrix
Description
I´m not sure whether this is a bug, but I think so:
If you change the number of days to show (In German: "Anzuzeigende Tage"; not the length of the week in general), you will skip some days when scrolling.
Example:
Maybe this behaviour is intended, but i would change weekwise scrolling to use the number of days shown on screen to make it more usable in such a case
There are some errors thrown when using the custom amount of days to show.
Additional information
This is a known bug and being worked on.
The issue is just to prevent future bug reports.
Description
APP crashes immediatly after opening it. Works in both OpenUntis and Untis Mobile.
Actual behavior
Open app, timetable and user information loading in background, BetterUntis shows Dialog with crash report, Android shows "APP crashed"-popup
Expected behavior
Don't crash
j.c.d0.s: Invalid JSON at 49831: Expected string or non-null literal
at j.c.d0.w.e.c(Unknown Source:14)
at j.c.d0.w.k.n(Unknown Source:2)
at j.c.h.b(Unknown Source:2)
at com.sapuseven.untis.models.untis.timetable.PeriodExam$$serializer.deserialize(Unknown Source:61)
at com.sapuseven.untis.models.untis.timetable.PeriodExam$$serializer.deserialize(Unknown Source:0)
at i.a.a.a.t0.m.z0.a(:64)
at j.c.d0.w.k.a(Unknown Source:2)
at i.a.a.a.t0.m.z0.b(Unknown Source:8)
at j.c.d0.w.k.b(:6)
at j.c.h.a(Unknown Source:5)
at com.sapuseven.untis.models.untis.timetable.Period$$serializer.deserialize(Unknown Source:405)
at com.sapuseven.untis.models.untis.timetable.Period$$serializer.deserialize(Unknown Source:0)
at i.a.a.a.t0.m.z0.a(:64)
at j.c.d0.w.k.a(Unknown Source:2)
at j.c.h.b(Unknown Source:5)
at j.c.c0.a0.a(Unknown Source:8)
at j.c.c0.a.patch(:3)
at j.c.c0.a.deserialize(Unknown Source:10)
at i.a.a.a.t0.m.z0.a(:64)
at j.c.d0.w.k.a(Unknown Source:2)
at j.c.h.b(Unknown Source:5)
at com.sapuseven.untis.models.untis.UntisTimetable$$serializer.deserialize(Unknown Source:74)
at com.sapuseven.untis.models.untis.UntisTimetable$$serializer.deserialize(Unknown Source:0)
at i.a.a.a.t0.m.z0.a(:64)
at j.c.d0.w.k.a(Unknown Source:2)
at j.c.h.b(Unknown Source:5)
at com.sapuseven.untis.models.untis.response.TimetableResult$$serializer.deserialize(Unknown Source:50)
at com.sapuseven.untis.models.untis.response.TimetableResult$$serializer.deserialize(Unknown Source:0)
at i.a.a.a.t0.m.z0.a(:64)
at j.c.d0.w.k.a(Unknown Source:2)
at i.a.a.a.t0.m.z0.b(Unknown Source:8)
at j.c.d0.w.k.b(:6)
at j.c.h.a(Unknown Source:5)
at com.sapuseven.untis.models.untis.response.TimetableResponse$$serializer.deserialize(Unknown Source:127)
at com.sapuseven.untis.models.untis.response.TimetableResponse$$serializer.deserialize(Unknown Source:0)
at i.a.a.a.t0.m.z0.a(:64)
at j.c.d0.w.k.a(Unknown Source:2)
at i.a.a.a.t0.m.z0.a(Unknown Source:5)
at j.c.d0.a.a(Unknown Source:17)
at d.a.a.a.a.c.a(:38)
at d.a.a.a.a.c$d.b(Unknown Source:13)
at i.w.j.a.a.a(Unknown Source:9)
at j.a.a0.run(:11)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6746)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Additional information (please replace)
If the timetable cannot load in the morning because there is no internet connection I get a notification "Failed to load Timetable - You wont get any notification today" even if the notifications are disabled in the settings.
Anfragen-ID: 8
Fehlercode: 2
Fehlermeldung: Read error: ssl=0x6f88ae4c88: I/O error during system call, Connection reset by peer
Breaktime supervisions are not shown in the teachers timetable. It would be nice to implement this.
Thanks for your amazing work so far.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.