cuis-smalltalk / cuis-smalltalk-dev Goto Github PK
View Code? Open in Web Editor NEWActive development of Cuis Smalltalk
License: MIT License
Active development of Cuis Smalltalk
License: MIT License
If you want to show all underscores as such (ASCII69, Unicode, most modern systems), everywhere, evaluate:
StrikeFont useUnderscore
If you want to get left arrows (ASCII63, classic ST-80), evaluate:
StrikeFont useLeftArrow
Maybe you also want to see variable assignment as :=
. For this evaluate:
Preferences enable: #syntaxHighlightingAsYouTypeAnsiAssignment
Note: By default, Cuis accepts underscores as assignment, and also as part of selectors and variable names. This works independently of the choice of the glyph to be shown. There are also preferences for controlling this.
ML
Add a note in the class documentation
Hi Dan,
On 7/15/2015 12:54 PM, Dan Norton wrote:
Maybe it's my dyslexia, but isn't this backward?
It is not you. It is the unfortunate fact that 2 conventions exist for this
"Array2D newSize: 2@3" produces an array with 3 rows and 2 columns:
| nil nil |
| nil nil |
| nil nil |
Yes. 2@3 is a point with x=2 and y=3. x is usually regarded as the horizontal coordinate and y as the vertical coordinate. This is the universal convention for pixels in Displays and Forms and for mathematical points in the Cartesian plane.
IMO it should be:
| nil nil nil |
| nil nil nil |
Yes. That's why Array2D class also has #height:width: and #width:height. Matrices are usually accessed with i, j; where i is the row and j the column. Array2D instances have #x:y: and #i:j: , and the order of the arguments is swapped. So you can pick the convention that bests suits what you are doing.
For example, in Squeak, "MatrixTransform2x3 identity" produces: MatrixTransform2x3(
1.0 0.0 0.0
0.0 1.0 0.0
)
Yes. It uses the matrix convention.
In addition to all this Matrices have origin (1,1), while the mathematical plane and Forms have origin (0,0). But Matrices and Forms have the origin at the topLeft, while the mathematical plane has the origin at the bottomLeft (or at the center if you allow negative coordinates).
To make things even more complicated, when mapping the mathematical plane to a Form, you can map integer numbers in the plane to the center of the pixels (the convention that makes most sense to me) or to pixel corners (as Squeak / Cuis Rectangles do).
All unnecesary complications, but that we can't avoid.
LinearAlgebra.pck.st
Use Matrix instead of Array2d.
(whew)
No, you are not wrong.
But use Matrix, or maybe FloatMatrix if it makes sense for you.
Also keep in mind that Cuis has AffineTransformation, that is almost identical to Squeak's MatrixTransform2x3 (except for Squeak's doing some very arguable rounding to integer of results).
Possible typo?
'Can not debut a terminated process: '
should be
'Can not debug a terminated process: '
The current 'mail list' link points to the old list archive/mailman interface at http://jvuletich.org/mailman/listinfo/cuis_jvuletich.org
It should point to
http://cuis-smalltalk.org/mailman/listinfo/cuis-dev_cuis-smalltalk.org
I also think it would be good to keep the link to the old archive somewhere,.
Transcript gives UndefinedObject(Object)>>doesNotUnderstand: #topLeft when resizing the world in a way that places it outside the view. I dug around, but it looks like this is due to the morphic changes and I'm not sure what the path forward is.
From ML:
On Mon, 2015-03-09 at 05:54 -0400, Phil (list) wrote:
- Morph stepping appears to be non-functional (at least in terms of
running the code as-is from Cuis 4.0)
Figured this one out... #step appears to be obsolete, use #stepAt:
instead. In some cases now need to override #wantsSteps to return true
(the default implementation now always returns false. This is an issue
only for some of my animated morphs.)
Maybe a better solution would be to just disable keystrokes that modify
the text, but not others (arrow / scroll wheel, selection and clipboard
commands, etc).
Juan Vuletich on ML Wed, Jan 28, 2015
You don't really need a new class. This works:
model := TextModel new contents:
'Hi folks, \this is a multiline text, \see?' withNewLines .
doWrap := true.
m := TextModelMorph withModel: model.
m wrapFlag: doWrap.
m hideScrollBarsIndefinitely.
m lock.
m openInWorld
Things to do
The included image shows the Taskbar but no windows in it.
Taskbar hide followed by show does not help.
Hi,
bin/copyImage.sh tries to copy Cuis4.2-2203, whereas current version is Cuis4.2-2336.
According to
http://www.fileformat.info/info/unicode/char/a4/index.htm
The expression
Character unicodeCodePoint: 164
should evaluate to the Euro symbol. But instead it evaluates to nil
.
Hello @jvuletich,
I'm at Camp Smalltalk with @KenDickey and we discovered that the headers in CodePackageListWindow
clips when using the Very Large font setting.
We made a small changeset to fix this, but we also see that a similar issue can be found in the ChangeSet editor.
for example this one.
There is some issue with the caret on bold text. It blinks by changing the width instead of vanishing. It also looks slighty too low.
The readme says:
mkdir CuisDevelopment
cd CuisDevelopment
git clone https://github.com/Cuis-Smalltalk/Cuis-Smalltalk-Dev.git
Cuis-Smalltalk-Dev/bin/newImage.sh MyProject
First, the script isn't executable. Second, it fails immediately saying the image already exists. I tweaked the script to print what it thought the image path should be and it replied with ".".
Juan on ML Tue, May 19, 2015
The CompatibilityPackages
folder is for SqueakCompatibility.pck.st
, and any other packages that depend on it. VMMaker
, for instance, is a verbatim copy of current (i.e. May 2015) VMMaker for Squeak, without a single line of code changed. But this is open for discussion.
Add reference to source (including version number) of VMMaker
Squeak and Pharo allow to specify expected failures in SUnit tests. An expected failure is green when it fails and red when it succeeds. This is very convenient for bugs that cannot be fixed easily. It allows to ship a release with all tests green.
Compatibility with the Squeak and Pharo implementation would be good to easy porting.
Morphs should be copied using #copy.
I do not know the historical background, but Object>>clone invokes #primitiveClone
in the VM. This is an efficient shallow copy, in which the object header and data
fields are copied to a newly allocated object, and the object hash and GC bits
are updated in the new copy.
The original Object>>copy would work where I implement postCopy to set location to a new MorphicTranslation.
Object>>copy
^self shallowCopy postCopy
I searched a bit more and found http://lists.squeakfoundation.org/pipermail/vm-dev/2014-February/014683.html and the more detailed http://lists.gforge.inria.fr/pipermail/pharo-project/2010-January/019801.html (by Levente).
After these references, I decided to remove #clone from Cuis. Most senders were replaced by sends to #shallowCopy (it uses the same VM primitive). But for several, calling #copy works the same, and #copy sounds more natural to me. I also refactored several implementations of #copy et al, in SequenceableCollection and AbstractSound hierarchies. Will commit to github soon.
I think that this must have been done for efficiency, to provide the fastest
possible means of shallow copying an object. The methods in the VM and in Object
are both old enough that they had no author initials, so this was a very early
optimization in Squeak.
Object>>clone can be replaced by #shallowCopy. Perhaps it is time to
deprecate #clone.
Juan is removing it from Cuis, with reference to this summary by Levente:
http://lists.gforge.inria.fr/pipermail/pharo-project/2010-January/019801.html
My point is that usually we don't really need closures:
a) For control flow, all we need is code blocks. The compiler knows that, and optimizes most cases, avoiding the creation of a real closure. These are never serialized by themselves (maybe the complete method is serialized).
b) Real closures. Used for new control structures, that the compiler doesn't know about. Also used for functional programming and continuations. Not really needed most of the time: Squeak existed without closures for over 10 years. These are hard and expensive to serialize.
c) "context free lambdas" a.k.a. "clean closures". State is stored in objects. All state is passed to the block as arguments. These are easy and cheap to serialize. A typical example for these is a sort block in a SortedCollection.
The code you sent me uses b). It stores state in variables in the context of the closure. But this is not really needed. I could convert your code to c). See the attach. What I did is to take that state and store it in an instance variable. There was yet another variable that could simply be a temporal inside the block. Then, the default implementation of Morph>>copy worked without problems.
I think it would be good to have different syntax for "clean" or "context free" blocks. And encourage their use above real closures, whenever possible.
Well, but Morph is the same as your automobile. Copying a morph (usually) means copying submorphs. But not owner (otherwise, the whole World gets copied). This is taken care at Morph >> storeDataOn: I know this is rather hidden, code is not really clear, and maybe some framework to handle "creation relations" would be in order.
The shallowCopy postCopy approach works only for objects that don't form graphs. For these, the issues of duplications appears. The old #veryDeepCopy from ST-80 was complicated, and it had problems. I claim:
appropriate semantics for copying is usually a matter for each object to define. That's why it is ok to copy the #copy method from Object to your morph if appropriate.
The problems of duplication, identity, etc, are the same for copy as for serialization. That's why it is ok to use a serializer to copy graph objects.
So, I recommend (as general advice) to use clean closures if at all possible (as I said in the other thread), and to use the serializer to copy objects that form graph structures (like morphs). But, as #copy semantics is a responsibility for each object to provide, if this general advice is not applicable, instead of calling #shallowCopy, or creating new copy messages, I recommend implementing #copy appropriately for each class.
I hope all this makes sense for you.
Very good sense, but for #clean I would substitute the term #trivial, which makes more sense in this context.
After all, closures are called closures because they "close over their environment".
Trivial closures are more akin to Traits. We could split closures, including nested closures, into trivial code blocks and their associated environment vectors.
The basics are covered in:
http://www.iro.umontreal.ca/~feeley/papers/FeeleyLapalmeCL92.pdf
This 2b02227 commit added 32 mathematical symbols.
Review and update Unicode notes
https://github.com/Cuis-Smalltalk/Cuis-Smalltalk-Dev/blob/master/Documentation/UnicodeNotes.md
to describe current status.
To reproduce:
Neither ctrl-d or ctrl-p are functioning as expected. Both respectively print a 'p' or 'd' to the screen, instead of issuing a do-it or print-it.
Tested on Ubuntu 13.10 and Win 7 with multiple VMs.
In Cuis 4.2 if you click on a window title the hand grabs the whole window and moves it. You have to click again to let go again. I constantly move windows although I don't want to. This is quite annoying. In Cuis 4.0 the behavior was different.
Looking at the README.md contributing section
( https://github.com/Cuis-Smalltalk/Cuis-Smalltalk-Dev#contributing-to-cuis ), I'm getting a 404 errors for both:
http://www.cuis-smalltalk.org/CodeManagementInCuis4.html
and
http://www.cuis-smalltalk.org/CuisAndGitHub.html
KenD to ML
[email protected] Wed, Nov 11, 2015 at 5:13 PM
Cuis has been taking steps toward Morphic3:
https://github.com/Cuis-Smalltalk/Cuis-Smalltalk-Dev/blob/master/Documentation/NotesOnMorphic.md
The MorphExtension class was removed. (We have Morph Properties).
Morphs have float rather than integer location coordinates.
Morph location is relative to their owner, not the screen.
These are relatively small changes to get used to.
More radical are some of the other simplifications in the system.
The best example here is probably Layout.
LayoutMorphs do just that for their submorphs. A LayoutSpec is attached to individual Morphs to tell their container how they want to be layed out. See the class comments.
The code in LayoutMorph is much smaller (see LayoutMorph>>layoutSubmorphsHorizontallyIn:) than corresponding layout code in Squeak or Pharo.
See LayoutMorph class examples.
If you git clone the Morphic-Misc1 package and load it you can get Layout editors:
Open a shell and cd to the directory containing Cuis-Smalltalk-Dev
git clone https://github.com/KenDickey/Cuis-Smalltalk-Morphic-Misc1.git
Go to Cuis-Smalltalk-Dev, open an image and use a Workspace to require the package:
Feature require: 'Morphic-Misc1'.
Then use the LayoutMorph class examples, select (sub) morphs, open a LayoutMorph Editor (or a LayoutSpec Editor) and play with the settings.
Note that these editors are "one-shot" and will close after setting or cancelling, so click on the "push pin" in the upper right corner to keep them open.
If you have several editors open, you can use the "Show Halo" button to see which Morph an editor is adjusting.
Is there any documentation on how to use it, or is it allInTheCode ?
See the above URL and continue to ask questions. We need to make the documentation better over time and questions are very helpful here.
-KenD
(same question applies for symmetric case of vertical layout)
Basically:
it would seem more logical to me that the second case should behave like the first - height of the elements should be calculated in proportion to all the added morphs rather than only to the height of the container
Example:
| pane rect1 rect2 |
pane _ LayoutMorph newRow separation: 5. "1"
pane addMorph: (StringMorph contents: '1').
rect1 := BorderedRectMorph new color: (Color lightOrange);
layoutSpec: (LayoutSpec proportionalWidth: 2.0 fixedHeight: 30 minorDirectionPadding: #center).
pane addMorph: rect1.
rect2 := BorderedRectMorph new color: (Color cyan).
pane addMorph: rect2
layoutSpec: (LayoutSpec proportionalWidth: 0.5 fixedHeight: 30 minorDirectionPadding: #center).
pane
color: Color lightGreen;
openInWorld;
morphPosition: 320 @ 50;
morphExtent: 180 @ 100.
pane _ LayoutMorph newRow separation: 5. "2"
pane addMorph: (StringMorph contents: '2').
rect1 := BorderedRectMorph new color: (Color lightOrange).
pane addMorph: rect1
layoutSpec: (LayoutSpec fixedWidth: 20 proportionalHeight: 2.0 minorDirectionPadding: #center).
rect2 := BorderedRectMorph new color: (Color cyan);
layoutSpec: (LayoutSpec fixedWidth: 20 proportionalHeight: 0.5 minorDirectionPadding: #center).
pane addMorph: rect2.
pane
color: Color lightGreen;
openInWorld;
morphPosition: 520 @ 50;
morphExtent: 180 @ 100
See how in the first case the orange morph is 4 times as big as the other (since proportionalWidth is 2 vs 0.5 of the other morph), which in the second example the height is just such that the orange one is just two times as tall as the row. This can be seen as well resizing both layoutMorphs...
Am I missing something?
To reproduce:
To reproduce:
The same happens with many commands in the context menu. In Cuis 4.0 this worked.
Luciano Notarfrancesco wrote to the ML
About my recent changes, some of them are 1) extensions to Theme to be able to customize some more aspects of how the windows and widgets look, or 2) fixes for small bugs that I found on the way, like misalignments of a few pixels between parts of a widget or a window. The motivation behind this was just to be able to implement a very minimalist look (borders of just 1 pixel, no decorations, no icons, no anything that I dont need and takes up screen real estate), and a sort of tiling dynamic window manager very much like http://dwm.suckless.org
https://github.com/len/Cuis-Smalltalk-DWM.
In order to implement this "window manager" as an external package with minimal changes to the core system, I decided to: 1) make the current Theme receive messages #windowOpen: #windowClosed: every time SystemWindows are open or closed, in order to give it a chance to implement window-management behaviour or delegate it to a proper window manager; 2) move the window-management keyboard shortcuts (like alt-w to close) to Theme, so it is all in one place, easy to change, and easy to make a Theme that delegates keyboard events to a proper window manager.
Again I did it like this in order to minimize changes to the core system. At the moment window management is in part implemented in SystemWindow, and also in HandMorph and Morph. I had to make some small modifications in order to get the desired behavior when using DWM, and keep the original behavior in the base system. Maybe in the long run we would want to have a WindowManager class that do this, handle keyboard events for the window-management shortcuts and receives #windowOpen: and #windowClosed:, etc. But I would like to think better about this before adding new concepts and complexity to the core.
Loading and opening a ColorEditor generates a fractional coordinate which causes draw failure in color slider.
People sometimes ask what the name means.
Refer to
https://en.wikipedia.org/wiki/Southern_mountain_cavy
KenD on ML
"The Installed Packages browser used to be able to require a minimum revision on the base release.
I use this feature as a backstop when features change in the base release.
Any chance in getting this ability back?"
J. Vuletich (mail lists)
[email protected] Wed, May 13, 2015 at 2:08 PM
Reply-To: [email protected], Pharo Development List [email protected]
To: Pharo Development List [email protected],
The Cuis image is now in Cog format (6505) instead of Closures format (6504). I hope this allows you to run Cuis in your system.
Clarify in README.md
From the ML
Juan Vuletich
[email protected] Fri, Oct 23, 2015 at 8:49 PM
Reply-To: Discussion of Cuis Smalltalk [email protected]
To: "[email protected]" [email protected]
Reply | Reply to all | Forward | Print | Delete | Show original
Hi Folks,
I've just updated github. I did many changes, to adopt FileMan almost everywhere in Cuis and core packages.I did a few changes to FileMan and the API. The one you might notice is that I've made FmFileEntry and FmDirectoryEntry siblings, under a new FmEntry. Now, each class is more specific: FmFileEntry doesn't handle Directory responsibilities (like creating files in it) and FmDirectoryEntry doesn't support File responsibility (like creating a FileStream on itself). I think it is much cleaner this way. The change you might need to care about is that
'dirName' asDirectoryEntry / 'subdir'
answers an FmDirectoryEntry
and the new #//:
'dirName' asDirectoryEntry // 'filename'
answers an FmFileEntry.
Please adapt your packages to the new FileMan API, as the old FileDirectory hierarchy will be deprecated soon, and later removed from Cuis.
Cheers,
Juan Vuletich
On 7/15/2015 8:43 PM, Phil (list) wrote:
Is there a setting that will disable this substitution? I would
actually prefer it to go the other way: if it sees an _ assignment,
replace it with :=
JV answered.
Please check #syntaxHighlightingAsYouTypeAnsiAssignment and #syntaxHighlightingAsYouTypeLeftArrowAssignment . Both default to false.
Would turning on #syntaxHighlightingAsYouTypeAnsiAssignment be enough for you?
Update FAQ entry or note
From ML:
Add examples to 'useful expressions' workspace which show
T1. canonical examples of how to compress/decompress files/streams
T2. package loading through code.
Phil writes "I've been calling CodePackageFile
installFileStream:packageName:fullName: but that no longer appears to be
the correct entry point if I want dependency checking"
In Pharo 4.0
$b digitValue
evaluates to
11
and so does
$B digitValue
In Cuis
$b digitValue
evaluates to wrongly to
-1
whereas
$B digitValue
is fine
First CursorWithAlpha class>>buildBiggerNormal
signals "image format not recognized" eventually killing the UI
Ad some notes to https://github.com/Cuis-Smalltalk/Cuis-Smalltalk-Dev/tree/master/Documentation for learners how layouts work in Cuis.
Tentative title
Some suggestions for Cuis Morphic experiments for learners.
KenD to ML
Ken.Dickey
[email protected] Sun, Mar 29, 2015 at 4:26 AM
On Sat, 28 Mar 2015 18:47:04 -0400
"Phil (list)" [email protected] wrote:
I’ve been looking up Squeak/Pharo/Cuis documentation on using layouts
(which may be the issue) but have made little headway.
Cuis layouts are different from Squeak or Pharo. Given the changes going on, many things require some code reading and playing around.
To understand Layouts and LayoutSpecs, I did simple editors for them. They are located in the Morphic-Misc1 package at:
https://github.com/KenDickey/Cuis-Smalltalk-Morphic-Misc1
From the readme:
"
After loading this package, one can select a morph, open its menu from the halo, and edit its LayoutSpec.
If the morph is a LayoutMorph, one can also open an editor for the LayoutMorph from the halo menu.
"
Inspecting the window submorphs should help as well.
Cheers,
-KenD
To reproduce:
DSA has several problems. The usual version leaks the private key if the ephemeral key has any deviation from randomness. Furthermore, the version implemented by Cuis uses SHA-1, which is considered weak. Finally, Cuis implements DSA in Smalltalk, which potentially increases vulnerability to side-channel attacks.
A much better algorithm is EdDSA. It is very fast, provides 128 bit security, and major implementations are immune to side-channel attacks. While implementing it in Cuis would be far too complex and error-prone, there is no need to do so; instead, the FFI can be used to call out to libsodium, which is a portable, well-regarded cryptography library.
From:
J. Vuletich (mail lists)
[email protected] Sat, May 9, 2015 at 5:17 PM
To: Pharo Development List [email protected]
Hi Folks,
(below)
Please take a good look at Cuis' Transcript and consider using it.
By default, the display is updated immediately, but without calling Morphic, it can even work with no UI framework at all. It does updates faster than Squeak or Visualworks:
Time millisecondsToRun: [ 1000 timesRepeat: [ Transcript show: 'x' ] ]. 763.
But if you want minimum overhead without immediate feedback:
Time millisecondsToRun: [ Transcript showOnDisplay: false. 1000 timesRepeat: [ Transcript show: 'x' ]. Transcript showOnDisplay: true ]. 1.
"As fast as Pharo"
It is also thread safe, and for Ben's example:
Transcript clear.
[
$a asciiValue to: $z asciiValue do: [ :c |
[ 1 to: 9 do: [ :i | Transcript show: c asCharacter printString , i printString , ' ' ] ] forkAt: 40
].
] forkAt: 41
it gives the same result as Pharo.
The fact that the updates are not bound to Morphic also means that it is possible to do #show: deep in Morphic logic, without causing infinite loops or recursions, and get immediate feedback. It has proved to be a useful aid in debugging Morphic code.
To reproduce:
(from an email to the Cuis mail list)
In Squeak, 'someDictionary asSet' answers a set with the values. It should do the same in Cuis, (like Dan and Nicolas want). Maybe we'd also adopt the idea of having HashedCollection as a superclass of both Dictionary and Set, just like in Squeak.
Any takers?
DisplayObject supplied #slideFrom:to:nSteps:delay: which is used in card animations in Soltiare.
As DisplayObject no longer exists, we need to recreate this functionality.
Ideally, we should do something akin to the W3C SVC spev (See Chapter 19 in http://www.w3.org/TR/SVG11/ ).
Phil on ML
In an empty area in the world, middle click to bring up a halo for the
world PasteUpMorph. Middle click again... MNU.
Hi Juan,
Is there a reason why you included not only the latest image version 2135 but also two older ones 2093 and 2107? I would prefer if you switched back to only include the latest version to make the shell script easier again.
Cheers,
Bernhard
Phil writes on the ML:
previously: (4.0)
#step
now: (since 4.2)
#stepAt:
(just rename #step to #stepAt: milliseconds)
#wantsSteps (^true)
Notes:
previously:
#handlesKeyboard
(^ true)
#keyboardFocusChange:
"(call any code needed to deal with getting/losing
focus such as drawing a focus indicator)"
#handleKeystroke:
"(when morph has focus, will receive keystroke)"
now:
This is my best guess... are there any examples of working Morphs that
deal with keyboard focus but do not have text morphs?
#handlesKeyboard (no change)
#handlesMouseOver:
(^true to get #mouseEnter: & #mouseLeave:)
#mouseEnter: event
event hand newKeyboardFocus: self
#mouseLeave: event
event hand newKeyboardFocus: nil
#keyStroke: event
"(receives the keystroke when focused, some event accessors no longer exist)"
One additional thing related to keyboard focus that should probably be
handled by Morphic: various mouse (mouse wheel) and trackpad (gesture)
events get sent as keyboard events and should probably be (at least
optionally?) intercepted from the event stream and sent as distinct
events such as #scroll: etc. No idea how multi-finger touch screen
gestures are handled by the VM these days but that is yet something else
to think about...
Bring up code which uses a OneLineEditorMorph (e.g, package in Cuis-Smalltalk-IA-EN).
Try to use the OneLineEditor instance.
Add a note like:
Cuis has the Sound system of Squeak in Package.
Load it with
Feature require: 'Sound'.
Then play a melody with:
(AbstractSound noteSequenceOn:
PluckedSound default from:
#((c4 1 500)
(d4 1 500)
(e4 1 500)
(g4 1 500)
(a4 1 250)
(a4 1 250)
(c5 1 500)
)
) play
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.