Conf42 JavaScript 2020 - Online

- premiere 5PM GMT

Using Our Own Custom Graphics Library to Show Them Analytics!

Video size:

Abstract

Already got bored of those using those default graphics libraries like Canvas? Why not create your own Graphics library then?

This talk will show how to create a graphics library from scratch and how to best use the latest tools in Javascript to best add on to make it a ready-to-use product!

Summary

  • Reinaldi is a founder of GrEs Studio and a developer advocate in the tech community. His personal field of interest is in penetration testing, intrusion and other security related best practices. He also is a VR tech enthusiast, so he loves exploring developments in new VR applications.
  • When we create graphics libraries, we need to ensure that the libraries we have can portray clear message. Clear, concise visuals is a must. Second off, provide novel elements. Third, follow the errors guideline.
  • I'm going to be showing a bit about how I implemented my own library directly for my own use case. In this particular context, I'm implementing it for being able to record data based on data that I've collected from my sensors. Define core functions for the graphics library. Finally execute, put into motion, draw it on your website.
  • All right, the first step of the whole process, initialize variables. This is because we have eight different kinds of data that we are obtaining and eight different graphs we want to draw. And the other functions will be talked about later as we go along these implementation.
  • The code starts off with a getaxml HTTP request object function. This can be used to recognize if the browser that is being used is an Internet Explorer browser or if it's another browser. Next we need to draw basic graphic drawing background. This is not making as much sense right now, but I'm going to show the visualization at the end.
  • So some of these functions include stuff like getobserver data, got web server data and get web server all data. And afterwards we then have a display all data function. This will display data in those form of rows and that's for another segment of the website. This is part of the adaptability feature that the graphics library aims to have.
  • We define a function called draw line graphics. What we do is basically based on the graphics libraries. We then round up the timestamp period for the data which is still within a particular period of time. And this will help us to portray the data in a much more efficient way.
  • We start with our customs graphic library. We've finished making our graphics library specific functions. Now we just have to start putting it all together and making the Ajax requests. And this can be then put into motion in HTML, which I will show in the next slide.
  • Thank you so much for listening to my talk. Remember to connect with me if you have any questions, or if you would like to talk to me about anything else I mentioned before. I hope you enjoy the rest of the talks at the conference.

Transcript

This transcript was autogenerated. To make changes, submit a PR.
Hello everyone, my name is Reinaldi and I'm going to be giving the talk using our own custom graphics library to show them naltics. So before we begin, I'd like to give a big thank you to Mark and rest of the Conf 42 team for organizing this amazing conference. And I'm using to be enjoying learning from every one of the speakers here. So I hope that you guys can enjoy learning from every one of the speakers here, as well as to enjoy my particular talk as well, and take some value out of it for your own needs. So let's get into it a bit about myself. I'm a founder and developer advocate, and I'm a founder essentially of GrEs Studio and I'm a developer advocate in the tech community. So I've been a speaker in the open source community for about four years now, and for the past four years I've been participating in various conferences talking about various issues and talking about best practices such as cloud based practices, security practices, and also just talking in general about projects that I'm working on, such as programming based projects based in Python or JavaScript, or more such as that. I'm a certified AWS solutions architect and DevOps engineer professional as well as a CCNA, and my personal field of interest is in penetration testing, intrusion and other security related best practices. So if you're interested in talking to me about it, I'm always happy to basically hear you out and basically have a good conversation with you about those topics. On those side I run meetups, those occasional hackathon, as I enjoy being able to learn from people in the hackathon, as well as to be able to encourage people to develop new solutions to solve problems within various issues regarding the community and in general. I also am a VR tech enthusiast, so I really love being able to explore developments in new VR applications and such. So if you are also an advocate of VR technology, and if you really enjoy developing applications as well within VR and such, then definitely chat me up. I'm really happy to talk about developments, my own developments, and also in general, what developments there currently are in the community and how we can best proceed with further VR technology. So first off, we're going to start off with talking about what to aim for in creating graphics libraries. So first off, clear, concise visuals is a must. When we create graphics libraries, we need to ensure that the libraries we have can portray clear message. People should be able to interpret what we are writing easily inside those libraries. People need to be able to see the graphics libraries, the graphics that are portrayed from these libraries and just think, oh, right, it's going to portray this particular threshold amount, or it goes from x to Y and it's trying to portray this particular thing and we can see this particular pattern. So people need to be able to interpret your graphics libraries very well. So you need to keep that in mind when you create graphics libraries. Second off, provide novel elements. So when I say novel elements, I mean you need to put a distinguishing factor between you and the other graphics libraries. So you need to be able to have that. Why? Why should I use your graphic library in particular compared to other graphics libraries? What benefit do you have? For example, what benefit do you have over the standard canvas library? So it's all something that you need to take into consideration while you're making those judgments. And essentially, you need to have that why factor, and you need to also ask yourself, why do you make that particular library? Can you already actually have that libraries? Can you already actually do what you need to do from other libraries, or are you introducing something new that is not yet available in other libraries? Third, follow the errors guideline. And I'm using to be talking in depth about this in the next couple of slides. So before we go on, I need to stress that an accustomed library doesn't mean no dependencies. So when I say we're going to develop this from scratch, I don't mean that we will exclude other graphics libraries because reusability is a very important part of software development. If we actually have existing code that can actually help us in our development, why not we use that? Why got we use already existing libraries to also help us in developing new libraries. So some examples of this is chart js, canvas js, two js. So even if you're developing a new library, it doesn't mean that you can't use them. So the heirs guideline, it's a personal guideline which I established myself. So first off, you need to decide what the aim is. So when I talk about aim, I'm talking about why you have that library. What are you trying to accomplish with that library? So you need to have a clear aim, such as why do you need a new library in place, essentially? And what problem are you trying to solve with those library? Are you trying to visualize temperature data? Are you trying to visualize something else? It all depends on you information. What information do you want to display in the graph? You need to think about the types of information that you can display because each type of information can have different thresholds and different types of measurements. That you need to put in place. For example, say you will want to visualize temperature data or particle matter data, or the number of HTTP error responses. It all have very different graphical implications and essentially you need to consider those while you're going along, because every type of information have different implications on what it means for your particular use for making new graphics library. So you need to consider this while you go along. Resilience. Now, what comes to mind when resilience is mentioned in this particular instance, resilience is the adaptability towards various threshold stretches that may be encountered by a graphics library. Say for example, you have temperature data and in your particular city temperature data may only stretch between 20 and 30, but suddenly temperature may jump up to 100. How will you visualize that? Will you those to actually put in a zero to 100 on a scale and actually have that to 20 to 30 on a flat line? Or can you actually make those graphics library adaptable somehow to that particular instance? And that's what I'm going to be talking about as well later on and showing how you can make the graphics library adaptable towards changes in data such that structure. Structure, essentially in this kind of scenario means how will you structure your libraries? What kind of structure do you want your data to have? Do you want it to display a particular bar graph? Do you want it to display line chart? So essentially, how do you want to structure your data to an extent to make the data clear, to be able to be interpreted by people. So this is another very important factor that you need to consider while creating graphics libraries. All right, well, without further ado, we're just going to jump into the use case directly. So I'm going to be showing a bit about how I implemented my own library directly for my own use case. Now, to give you a bit of context, in this particular context, I'm implementing it for being able to record data based on data that I've collected from my sensors. So essentially how this works is that the data that I've collected will be sent from my device to web API cloud platform called Thinkspeak, which is then in turn sends the data to my visualization on my website. And that visualization has this custom graphics library implemented. So as I said before as well, dependencies are definitely okay. You need to strive to be able to use those kinds of implementations in order to make your life easier. So as you can see over here, those dependencies I particularly use are jquery 1.1 as well as canvas graphics library. Next up, you need to plan out your functionality so in my own personal use case, I have four steps, and this is how you plan out functionality for a graphics library which aims to retrieve HTTP requests as well from those server. So start off with you need first initialize the variables. You need to first initialize stuff such as what is the step size that you want to make in your graphs? What is your x minimum and x maximum, as well as the y minimum and y maximum. How do you want to scale your data essentially to be able to do this? Next up, define the web based functions necessary for the functionality. So these are examples of HTTP and Ajax requests. And essentially what you want to do is you want to be able to define in such a way that these functions are ready for you to use in implementation, and you can just call them and basically have them used as you go along. Define a core functions for the graphics library. Now this is where you start implementing the core functions, and I'm going to be showing you a bit about how to do it in the next few slides as well. But essentially you need to be able to show how to initialize the graphics that's going to be made on the site and other core features of the graphics as well that you use, and finally execute, put into motion, draw it on your website, start putting it into motion, and start retrieving data and such and start basically putting data into motion and start the whole visualization in motion. All right, the first step of the whole process, initialize variables. So as I mentioned, as you can see over here, we're initializing some pretty straightforward stuff, such as init. In this case, init simply is a state. So state is essentially a kind of a way to be able to initialize what particular element, if the graphics library is already drawn or not, based on the data that is received, and Ajax. In this case, we just declare it to be able to get XML HTTP request object. And as you can see for Ymax ymin y step, we have eight different values. This is because we have eight different kinds of data that we are obtaining and eight different graphs we want to draw. That's why we're specifying eight different values based on the particular maximum minimums that will most likely be associated with each particular type of graph. And we define a few more stuff, such as the data average period and of course also the sending data period, which is essentially the period of data that will be sent to thinkspeak, for example, from the device and specifying a time zone. We specify also a sensor data to also check if the sensor data is in or not and also specify a URL target. In this case it's the Thinkspeak website. And as you can see I specify my own channel and I'm going to show you how to be able to use this in your code later. And the other functions will be talked about later as we go along these implementation. So start off with, we start off with the old, good old getter, and that goes with the getaxml HTTP request object function should be really self explanatory if you're used to using Ajax in JavaScript, but essentially we're making an if else clause here. So we want to be able to recognize if the browser that is being used is an Internet Explorer browser or if it's another browser. So for Explorer and especially for the older versions, we need to actually put in an activex object for the Ajax request. If not, then we can assume that it's probably a new browser or new version of engine Explorer and we can basically call Ajax and instead take an XmL HTTP request. So essentially it works to serve both cases. So now we start off with having a function to initialize the graphics. So as you can see over here, we start off with needing to draw basic graphic drawing background. So we draw the x and y axis line, cross line and the y scale text with this particular start to the function. So that's why we have a for loop looping over eight times. So as you can see over there we have capturing variables of like x length, y length, and the increments that we want to take as part of the step sizes. So as you can see, we start also calling those canvas library that we already managed to import into the particular project in order to start converting string first and eventually start getting the element by id, to be able to get the particular graph by the id, and we start to use it to draw further functions. If you're already used to using the canvas library, some of these will be pretty straightforward, but I'm going to be just talking about these in general. So most people here can probably follow. So just some functions such as got context to get in clear rectangle, to be able to basically initialize the canvas width and canvas height based on our specified parameters, and some other customization stuff such as declaring the line width and the stroke style. So that's mainly for that particular part of the code. And essentially we have another for loop and this time we want to be able to draw the crossline background. So for this we start off by calling another for loop and basically putting it to the extent of until it reaches basically the step size that we put in place. So this will mean that it starts off with the y length and plus 20. So it'll continue on decreasing by the y increment value until it reaches ten. And this will mean that it begins the path and it'll continue moving towards the particular specified eye. To be able to draw the crossline in the background and the horizontal lines that are actually necessary. Same thing with the below feature. We also are drawing vertical lines this time, and we only draw the left and right most lines. And probably it's not making as much sense right now, but I'm going to be showing the visualization at the end, so it definitely will make much more sense by then. And for drawing the vertical line, as you can see at the bottom most code, we're going with continuing to begin the path and just moving the path, creating a line to the path and declaring more of the fonts, such as stroke, move to line to, and such. Continuing with that. As you can see, we have continuing modifications towards the font, and we start off by drawing an axis line. So this is where we draw the access line. We start declaring a line width and stroke style, and again begin path. So this time it's for the axis line compared to the other ones. And afterwards we then draw the text for the y scale. So we start off by declaring the normal font standards, such as declaring fonts first, fill style, fill a text, align, and basically afterwards just filling the text. And this is a particularly crucial part of the text. So as you can see, we have a wide difference variable there. So why do we need a wide diff variable? We need it for that adaptability purpose, as I mentioned before. So we're calculating the difference between y max and y diff in order to calculate the difference between the two. So essentially what we're doing here is we're adapting the particular text, the particular ranges by the new maximum and the new minimum. So basically we're scaling them accordingly. And that's what I was saying about adaptability. We want people to be able to see custom graphics library in such a way that they do not omit data, such as if we have a 100 when we have only a scale from 2030, so it'll scale the graphics accordingly and it'll put new measurements as required. And you don't have to worry about the graphics library going over the limit either, or actually kind of like being stuck with 100. Like only one point has 100, while all the other data has a 20 and a 30. Like sure, the data will be visualized, but because we put it on a period, data will eventually keep moving leftwards and eventually disappear, and afterwards it will scale back to 20 and 30 again. So outliers will still be displayed for a short moment, but in the end it'll be regulated to the point where we will go back to actually just having the standard library and actually going back to the standard measurement. So as long as we can still have a period where it captures the data, we're still able to represent the data correctly, but also still are able to make it adaptable to the point where we don't have to worry about that kind of data using neglected and not being taken into account of individualizations. Because who knows, some of those data may be necessary as well for if you need further data analysis to be done. And as you can see over here, that's why we have a y max minus y div for the fill text function and such. So some bored functions to add as part of the libraries. So some of these functions, as you can see over here, include stuff like getobserver data, got web server data and get web server all data. So getwebserver data in those case we are using that to be able to retrieve the data from the source URL through Ajax. Same as get web server for all data as well. Essentially got web server all data has a specified period of retrieving the web server data though gets web server data, is just opening a connection and being able to get the data in general and send that Ajax request. So as you can see, we're using our URL target variable here and we are opening it based on particular specified string on the URL that we have specified. So we're opening it and we're pushing a get request on either method. And as you can see, that's how more or less like both methods will work. And afterwards we then have a display all data function. So this will display data in those form of rows and that's for another segment of the website. So we can display the data in the form of graph, but you can also display it in the form of rows as well, should we require it. So for this one we are basically deleting the previous rows if there are any rows as well, which is why we have the delete row function as you can see over there. But before that though, we of course declare table length first and just go with the roast length variable that we declare. And further towards the bottom, we then declare variable as sensor data. And we want to parse the data that is obtained from those local storage. And that's why we have local storage, sensor data storage. And essentially if the sensor data is null, it'll just return null. But afterwards we just declare more variables as well, like the max length, the tail, body and row that is associated with the particular data. And continuing on from those, we then continue on to basically declare more of the variables in terms of the, to establish the rows and the table. So as you can see, we have declared s as kind of like the container for taking in the variables. And as you can see, we have different fields. We have field one, field two up to field eight, and that's where we basically start to take in the sensor data and portray it on the table. So to do this, we then get the element by id again, and we basically take up the row and we insert it as a row and basically it's inserted to the table that way, essentially towards the bottom. You then start comparing those data for each field data value for the current data row to the field maximum and minimum y values. As you can see, it's quite a long line of code, so it basically is just a list of while loops. So essentially it first checks out if basically the value is more than those maximum y value or less than a minimum y value. So it'll update the appropriate maximum and minimum y value accordingly based on fields. And as I mentioned before, this is part of the adaptability feature that the graphics library aims to have, so that you're able to adapt your particular library accordingly. And as you can see over here, we start to do it by doing the while loops. After checking that the sensor data does go above the y max or is smaller than the y min, and afterwards adjust the y min to decrease by a step if it's less than a minimum, or increase by a step if it's by a maximum. All right, and we then move on to making a function to draw. So now this is where it starts to get pretty interesting as well. This is where we start to put in a those drawing feature into the graphics library. So as you can see here, we define a function called draw line graphics. And what we do over here is we first initialize basically based on the graphics libraries, the graphic in it function that we already created before. So after this we then are able to set sensor data to parse from local storage again and set some more variables, such as the data sensor length or the x increments values and the current data period x length, y length. So these are all stuff that we will use as variables within the particular, within querying the data to be able to be received as part of the tables and the other implementations on the website. And also we also collect values such as previous y values and some values. And I'm going to be talking more about that a bit more. Well, when we see that code being used, variables being used in the code. So we then go on to declare for loop here. We go on to calculate the timestamps essentially at the created at field in the sensor data and convert it to minutes and divide by data average period. And then we finally round it. And you can see this by the formula that is currently there from the current data period. So we're essentially repeating this until the x pause reaches to bigger than or equal to 30, because 30 was the value we specified as those particular stopping point in the chart value in terms of those length that we want it to be. And afterwards we then loop over all those eight data and we then start to sum it all up. So essentially for this one, we then round up the timestamp period for the data which is still within a particular period of time. And we basically sum the value for every particular field. And afterwards we just kind of like raise the counter by one every time we finish that. So we're doing this to be able to average then those field sum values for the same time period, to be able to then portray the data as best as we can based on the averages that are done based on the sums of data. And this will help us to portray the data in a much more efficient way. And averaging those data helps us to keep track of the data better and be able to further develop better analytics based on the averaging data. And this especially helps us to steer clear of potential outliers and such. Continuing on, we continue on with another for loop for this function. So as you can see, for this particular one, we go on to basically average the field sum values as mentioned before continuing on from the last slide. And eventually we are then able to set the individual sum values and the individual sum values are represented by I as the index. So we have that formula in place to be able to take some values as those relative position from the bottom to plot drawing, and we added with 30 minus y towards the bottom, basically. Furthermore, from there we then continue on by using canvas Ctx and canvas Id again, and also declaring day, hour, minute, current time period and closest hour xpause values variables in order to further loop through all the eight graphics in order to start drawing the necessary graphics. So this is where we start drawing those tiny circle, for example on the spot point. And basically this is where we will start marking the particular points of data that has been recognized. So as you can see, we have similar stuff here as the previous slides, declan canvas id, canvas Ctx and begin path arc arcs where we start to actually put in the specific data. So as you can see, we're starting to draw center of a circle, center of circle, pause at the x pause basically at the exposition. And essentially from there we then put in those sum of values, the averaging, and we then basically go about it with creating it with radius three. And afterwards just some additional customizations, putting a red as the color of those particular circles and just filling it in. And we then have a conditional. So to check if the x pause is equals to x length plus 30, we then basically at the beginning of the graphic, which is the most right part, we then put timescale text in the canvas and basically get the day, hour and minute from the current at data to calculate the nearest hour to the end of the graph. So this will help us parse the data in terms of days, hours and minutes. And you can see the implementation towards the bottom and get the current time period and the closest hour towards the exposition that is currently made in order towards the current time period that is currently available. And initialize some more fonts for us to be able to visualize the kind of data. And yeah, continuing from there, just more fonts with font style text align. And also for being able to put a time mark for every 2 hours starting from the closest x hour position. We use the for loop looping, kind of like a mechanism for initializing the variable k as a closest hour exposition. And we continue on to put the time mark at the particular location where we have decided that we should based on the current part of k. And that's why we fill text at k. And we then go initialize the variable hour to display, to display the hour plus time zone and also check if the hour to display is bigger than recruit 24. And if so, we put it in a standard, kind of like a visualization. And afterwards we then fill in the text and we then do this to draw a vertical line at those point. And these vertical lines are going to make sense once you see the graphics visualization as well. So just standard stuff, just using move to line two and stroke again to be able to do so. And another check for if the hour is smaller than zero, then yeah, we'll just add to the hours, basically 24 to the hours. And this is where the tricky part starts we finished all our functions that we need to make. We finished making our request functions. We've finished making our graphics library specific functions. Now we just have to start putting it all together and making the Ajax requests. So in order to do this, we then start making an Ajax already state change function. So afterwards we then start to check if the statuses are currently already received correctly. And we do this by checking the Ajax status. So as you can see over there, if we put an Ajax status, if it's bigger than 200 and smaller than 300, or if it's actually those hundred and four, then yeah, sure it can got to go through, otherwise it'll just return an error. So afterwards we then go ahead with initializing a display data variable in order to check if the data is going to be displayed or not based on if the data has already been received. So afterwards we then check if the init variable is zero and in it, as I mentioned before, is a variable to check essentially if the data is already visualized. So here we are putting in variables as string sensor data to put a response text, putting a header length and essentially to be able to search through feeds to be able to retrieve the particular header length and essentially get also added to the time zone and also search for data n which we get by using the length function. And from there we then continue on by doing a window local storage in order to set the particular item as the sensor data storage and go on to declare another web get timer function to set an interval. And as you can see over there, we start getting the web server data. And with those we're basically putting 120,000 milliseconds, which is a two minute interval. So we're waiting for 120,000 milliseconds before we are actually getting to get the data that is retrieved. And since we already done it one time, we can basically continue on and set the inlet to one so that the routine will read the initial historical data will not run again and the new data will be available. So we'll set display data to one to enable to display the new data that has already been received. However, if the n is got one, not zero, we will just continue on with saving the new read data from the web server to a variable with the new read data function where we parse the JSON based on response text. And we then set sensor data to parse with JSON those local storage and get the sensor data storage from the local storage and we will get the id of the latest data and check whether it is the same with the latest one in the local storage. And we do this with the data length and latest id variables being declared and we go on to basically check if the new read data entry id is equal to the latest id and if so then we will add the latest data and store back to those local storage and we'll push that data and we will stringify that data and we will set the item as necessary and set the display to one, essentially as an alternate scenario to if the init was a zero. And finally we will start displaying the fields. So this is where we start creating variables such as create a transform, so new read data and created at time. And basically this is just to be able to set more variables, just to be able to check if the data was created at a particular time and basically to be able to display the current data results on the left side of those whole visualization, to be able to recreate as well the created data format that was made basically during the coding as well. So basically it's just checking when the created time was and just putting in behaviors, if so. And finally we can then display the data by doing a document get element by id and basically getting the data and displaying it in the new read data field. And this can be then put into motion in HTML, which I will show in the next slide. And that's pretty much all of it for being able to put the data into visualization. And of course some good HTML and CSS for supporting the JavaScript that we have already implemented. Because after all, HTML is our main pillar of support for our whole website. So as you can see, we're putting quite a number of our functions into play here. So we can start declaring the necessary construction of the table that we want of the latest variables you want. So as you can see over there, that's why we put number of fields to be displayed for the HTML code. And we also put the canvas library to motion as well here. And that's where we start drawing with our customs graphic library. We start basically drawing with canvas. Also the number of fields that are currently, we have currently already specified, and we also have the CSS. As you can see, we basically can specify more fonts that are necessary for use in the website and just declare more containers and labels. So I'm not using to be going too deep into this because we're focusing only on the JavaScript side. It's creating a JavaScript library after all, but it's just an example of how it's used on the HTML and CSS side and finally, it'll result in something like this. As you can see, we have our latest data on the left, our results on the right, our table of results, and our visualization of charts which we made using our own graphics libraries at the middle. And this is an example of when the whole visualization is populated with data. And as you can see, we have those small circles which we created through the function that we already defined on there. And as you can see, at first this is based on in it, but now after initializing it, after collecting data, it'll continue collecting new data and it'll continue moving toward the data towards the left, and it'll continue inputting new data from the right and it can adapt based on the maximum and minimum data, as I mentioned before. And that's what I mean by the data not being able to actually outlier data, not being able to ruin the data, because at some point with our specified interval it'll eventually be off those chart anyway. So it won't those much of a problem and it'll continue moving on until it's out of sight. So to wrap up, it's not hard to make your own libraries. Definitely takes a bit of practice, but once you know more or less like what you want to make, the aim errors, guidelines mentioned before, and pretty much just go ahead with it and just give it a try. And making a custom one is great, but remember that you can still use dependencies if needed. Don't be afraid to use a canvas as a dependency or two js or other canvas libraries that are available. As long as you are able to meet your particular objective and help solve a problem, then it's all good. And of course experiment, experiment, experiment. It takes a long while to be able to find the perfect library that can really match your needs. It takes lots of research, and if you're creating a library especially, you'll need to be able to research which dependencies you need as well, what tools you'll need, how to be able to best code it, and how to be able to make it most efficient. Even until now, I'm still looking for a way to make my library efficient as I share in the open source community. As one of the biggest things that you need to keep in mind in sharing these kinds of libraries is of course the readability and how the open source community can best perceive it. Because people won't really have a use for a library that is not able to be read clearly or actually is not easily understandable or has no function. So you need to experiment with the best approaches you need to make and how you can actually best approach it in the open source community to have people adopt the library and actually have them also use it for their own purposes as well. So that's all for me. Thank you so much for listening to my talk. And before we close up, remember to connect with me if you have any questions, or if you would like to talk to me about anything else I mentioned before. If you have any interesting insights about any of the topics I mentioned, or if you have any interesting insights about any of the topics code I've talked about, then feel free to share it with me. I'm happy as well to talk to you about it. So remember, you can connect with me with my twitter at Reynold G or through my LinkedIn at Reynoldsbroto. So thank you again, and I hope you enjoy the rest of the talks at the conference.
...

Renaldi Gondosubroto

Founder @ Gres Studio

Renaldi Gondosubroto's LinkedIn account Renaldi Gondosubroto's twitter account



Awesome tech events for

Priority access to all content

Video hallway track

Community chat

Exclusive promotions and giveaways