 Hi. It's good to be here. Thanks for having me here. So first off, I have no talent whatsoever in terms of making good-looking slides. So you're going to be stuck with the serious thing for the whole presentation, I'm afraid. So my presentation is in two parts. The first part to be forthcoming with you is going to be something of a plug for my company, Momocentral. You can find us at momocentral.com. I've been told that this would probably be relevant to some of you. If some of you are a freelance web developer or considering being a freelance web developer, that's the people that will probably be interested in and you might be interested in what we do as well. So that's going to be the first part and I'm going to jump into that. So I'm going to start this story at the long, long time of another long ago really. We used to be called Mokomomo and we used to be regular IT agency consultancies, whatever you call it nowadays, which is to say that people who need IT projects done, they come to us and then we'll sit down with them, we'll come out with pages and pages of specs for them, and then we'll give them a project manager, and then they'll agree to pay us a certain sum of money, and then we'll basically try to build something good for them. But it turns out that this is a shitty job. I don't know if any of you guys have done anything like this before, but it's pretty bad. I would have quit if we had to do it for one more year. So we went past that. So there are a lot of problems with this politics, politics, politics client. We can sit down all day and we can complain about how clients don't trust us. How clients are always constantly trying to get us to build stuff for free, how clients are delaying payments for the fourth or fifth month, and how clients are always trying to push blame on us, and then there's hidden costs because you need to manage this complexity. The complexity involved in agency work, there are two parts. There's the complexity of engineering, that's what you need to build for your client, and there's the complexity of managing their expectations, managing, making sure you don't lose out, making sure you don't go bankrupt, because the clients, they're used to not trusting the guys, so they will bankrupt you if they can. So which ends up being hidden costs because you need people who can do this thing, not just the guys who can do the programming work. So the money is split and then the product doesn't end up usually very nice even if you pay a lot of money because of all this extra stuff and sometimes bad decisions get made, happens all the time, feature creep, self-explanatory, outsource, exception, that's the term we kind of coined because we've worked with an agency before where it is extremely apparent that they have absolutely no real contact at all with the guys that are actually doing the work. So we literally were talking to people who are the project managers of the project manager of the project manager of the project manager of the project manager of the guy in India that's actually writing the code. So this actually happens, and it's really, really bad. So, yeah, shitty job. So we stopped after a while and then we sat down and we thought to ourselves, can we fix this? This is, the problems are structural. It's kind of set up to fail. The guys, the agencies who do well are those that do well in spite of how screwed up the whole thing is. So the question is, can we make contractual work actually work without having all of these terrible things happen? So that was kind of the problem we set out to solve, because after a few iterations, we settled on being a freelancer platform. There's a few reasons for it, we believe in small teams. So clients always think that when they have a big system, systems don't usually get very complex now. There's brief exceptions, of course, but big systems, they think that they need to get an agency that has armies of programmers, you know, standing behind them. But we were the guys who did some of these before and the truth is that you can have three guys just not sleep and you just, you know, get the thing done. So small teams are actually really good, right? So we believe in small teams and then we don't want layers of communication, right? So this is the thing about freelancing that the people do us, is a freelancer talking to the client, no more layers, right? That's it, right? And also, online workflows are happening nowadays. Internet is getting better, tools are getting better, right? And we're particularly inspired by free software communities, you know? There are people who are literally everywhere in different time zones and they can work together and build a good product, right? So these things are happening, right? These people need the tools and then they are really good programmers so they've made the tools, right? So we think that this kind of collaboration is going to become more widespread and the freelancers are the guys that are gonna benefit from it. So we started the freelancing platform. Of course, there's still some problems with freelancing. This might be familiar to some of you if any of you have freelanced before. So we started a freelancing platform and we made it our mission to make it as good as possible, of course, right? So we need to solve all these problems, right? So we design the process, the design of models of Pranthi around eliminating distractions, basically, right? We don't want people to talk about, we don't want politics at all. We don't want people to be hung up about billing and we don't want that kind of thing, right? So right now, this is kind of our pitch for freelancers that we are able to do now. You get paid, you get paid on time because we pay you, right? And then we build a client. So the goal is that you do not need to talk billing with your client. We take that completely out of the communication. You should be talking to your client about design, about code, about getting your product done, right? And no one paid future creep. This is another thing that we do insist on in our methodology is that we insist on paying by time, which is that if you put in 10 hours, you get paid for 10 hours. If you put in 20 hours, you get paid for 20 hours. We don't do a scope-based paying, so to speak, right? Because that's the source of many of our own nightmares back in the day, right? So we pay by time. And also, no bidding against cheap and bad people. We select our guys, right? Which I'll be talking a bit more about in the second part. But basically, we make sure all our guys meet a certain minimal level of algorithmic competency, right? And make sure that they have certain level of quality. And then we match make centrally. That means each client gets three profiles, four profiles, which we recommend for good fit, basically, right? And we negotiate rates and so on and so forth, right? So we're able to do some of these because of something we call real-time collaboration, which is to say that what happens is that you, the way you work with your client is that you agree on time slots with them, right? So in these time slots, you're like their employee. We encourage communication. We encourage them to check on you, to ask you for ideas, to call you for meetings, right? So that they know that you're doing your work, right? So in your time slot with them, you have to be available. You have to be working on their stuff. Full-time, no multitasking, right? But the result is a certain level of accountability that we can guarantee the client and so we can make sure that they pay up, basically, right? So, and then we have the talent manager, which is a guy that manages this relationship, right? So we don't do project management. We call it something different for, like, purposely, right? So what happens is that this talent manager is responsible for teaching the client, how to manage you if the client doesn't know how to, recommending tools, recommending processes, you know, the things that we found, right? The things that have worked for other people. We try to teach it to the client. Also, deal with disputes, negotiate rates, protect you in case of problematic clients. So we have the weight of the compensation on top of, that makes it a lot easier for us to negotiate instead of for individual freelancers to do it, right? So, basically, we designed the process to solve a lot of little problems here and there, but the overarching theme, right? Behind what we do is we want to remove distractions. We believe that contractual work should be about the contractual work. It should be about, you know, writing the code, getting the design up. That's what you should take up, like, 99% of your time. So our mission is to get rid of distractions, right? And, yeah, make freelancing great again, right? So... Yep, so, yeah, so, we're not capable of making America great again, right? So we'll leave that to more capable hands, hopefully. And, yeah, so that's the first part of my presentation. You can find us, find more information on MomoCentral.com, that's our website. If you want, you can stop me and talk to me about anything you want to know later on as well. I'll be around for a while, I think. So that's the first part, right? So, now we're going to go into something that's a bit more geeky, I guess. So, since this is a PHP meetup, right? So what I'm going to do is I'm going to talk about something we built, right? It's an interpreter, right, for a language called MocoM, right? Which is a toy programming language, it's Turing-complete and all that. That we invented, we built the only known instance of its interpreter. Actually, the guy sitting behind there helped us with it, so, yeah. So, yeah, we make our candidates do tasks in this language, so that's part of our selection process, right? So that's the kind of the function of this interpreter. So I'm going to talk about, briefly, about how the implementation details, how it works and stuff like that. So, roughly, you start with source code, right? That's the input of the whole program. And then there's a parser that parses it into an intermediary format. We call it RPN instructions, because it's mostly in reverse polish notation if you guys have ever heard of it. If you guys took programming class before, right? So I'll get to that while more. And then this intermediary instructions are executed by an execute function to produce a program output, right? So the nice thing about this architecture is that we can, theoretically, if we ever want to, we can change the language, the surface language features, the syntax features that's required by the source code. We just need to change the parser to parse it back into the same RPN instructions, and then we can reuse the execute mechanism, right? So the parsing, well, I'm not going to talk about the actual details of the parser. It's kind of token-based, and it's mostly string-processing, kind of boring stuff. But what it basically does is that it changes these kind of basic statements into something called RPN format, reverse polish notation, which is that the operator is at the end of the expression. So the regular arithmetic expression is called infix notation, which is that the operators are in between the operands. So when you change that to reverse polish, what happens is that the operands come first, and then the operator, right? So in this case, this means this one plus this one, and this one minus this one, so on and so forth, right? And then assignment can be something similar as well. Assign is an operator, right? So in this case, is you assign this to var i, right? And then this one is also you add one to var i, so on and so forth, right? And function is also an operator. So this is what we do to, this is what the parser does, right? It changes it into RPM. And then for more, how to say, special constructs in the language, like if statements, we have, we basically roll our own data structures that, so for example, if else, if else, right? We'll be stored as a data structure that contains an array of conditional expressions, right? Which are RPN, which are themselves translated RPN, right? And as well as an array of blocks, which are themselves, like translated into lists of RPNs, right? So roughly, basically, conditional one will decide whether block one gets executed, conditional two will decide whether block two gets executed, everything. So that's the intermediate format that we store. Functions, similarly, we have a data structure that contains the argument names, as well as the function body as a block of, as a list of RPN instructions, right? And then we assign that to the name of the function, right? So roughly what happens after the parser goes through everything is that you have the program as a list of RPN instructions, and with some of the RPN instructions containing their own kind of nested lists of more RPN instructions, right? So that's what happens after the parser is done. So next comes executing, right? So here's where we talk about why we put everything in reverse college notation, right? Because that lets us systematically evaluate very, like any kind of expressions, any arithmetic expression with any kind of complexity, right? So what you do is you simply go through the expression. If you find a simple data type, you push it on the stack. Simple data type is like numbers, you know, booleans, that kind of thing, strings. And if you find an operator, then you pop what you need from the stack as operands. And then you apply the operation on the operands, you get a result, you push that back on the stack, right? So how it works is for this example, for example, you go, you start from the left, right? You find 10, so you push that onto the stack. The stack is the stack data structure, right? And then you find five, you push that, you push five. So the stack now has five and 10 on it, right? Then you find minus, which is an operator. So you pop five, you pop 10, that's your operands. You minus that, and then you get five, because 10 minus five is five. So you push the result onto the stack. So the stack now has five, right? So we continue, we find seven, we push that as well. So the stack now has seven and five, then we find an operator plus, we pop seven, pop five, we compute 12, and then we push it back. The final result on the stack is the result of the evaluation, right? So this is how you evaluate RPN instructions, basically. And as for stuff like if, basically, we have it stored in a way that is easy to execute, right? So basically, we just evaluate each conditional, which is themselves each an RPN statement, right? So we do the RPN thing for each of the conditional, and for the first one for which we find a true statement, a true result, we will execute the block that is corresponds to this conditional. So if, for example, conditional two evaluates the true, we will execute block two. Block two is also a list of RPN instructions. We will just recursively call execute on that, and then go ahead, right? So, yeah, so if none of it returns true, then you execute the last one, which is the else block. You call execute on that list of instructions, so to speak, right? And for variables, we have a very simple implementation. We literally have a PHP associative array, you know, that functions as a variable table, right? So what happens is that this will just keep track of all the variable identifier names as keys and their values as values, right? So for example, when you execute an assign statement, right? So this is assign 10 to I, right? So you literally just assign 10 to the key I. So that keeps track of all your variables, right? And later on, when you need it to evaluate an expression, you just retrieve the key, the value for the key I, and then you use that, right? So that's simple variable support. And then that's kind of for one scope, right? So we have nested scope as well, for example, when you call a function. So what happens in the nested scope is that you have to, you have to have variable names in the current scope should take priority over the ones at the parent scope, right? So what we do is we just make a new variable table construct and we reference the old, the current one in the new one. So there's kind of a pointer linking the old var tab with the new var tab and then we execute the scope in using the new var tab. So when we do a retrieval in the scope, we will check the new var tab first for the variable. And if we find a value that will use that value, only if we don't find it, then we'll go back to the reference to the old var tab and then by so we will search the outer and outer scope until we get to the global scope. But if we don't find anything, we throw an error, right? So this is scoping and one more hoop we jump is that we support closures, which is actually not very hard to do in our framework, right? So closures, if you're not familiar with it, it means that your function scope remembers the referencing scope where it is defined. That means at definition time, that's the scope that your function remembers no matter what you call it. That's what closure basically does. You can kind of Wikipedia it if you need to. But so all we need to do to support that is when we execute the function definition, we will kind of, it's basically an assign, right? We make a function object that we assign it to the function name, but when we make the function object, we also add a reference to the bar at that point, right? So we remember the variable table at the point of definition, we store it in the function. So when the function is called, we retrieve that variable table again and then we add it as a reference to the new function scope so that it remembers, kind of. So when we call a function, we will make a new variable table with the function's argument names and then we will reference this back to the variable table that is stored in the function itself, which is what it was during this definition, right? So that's how we support closures. So yeah. So I'm kind of mostly done with implementation details. That's kind of the rough idea, right? So I don't think there's a lot more I can talk about it. So before I finish, I'm just gonna end with some thoughts on our implementation and on what, how PHP was like. We wrote this in PHP, we wrote this in Naked PHP, you could say, which is to say that we didn't use a framework or anything, right? So it was convenient because PHP is too, is very powerful in a certain sense, but perhaps it is too convenient, right? For example, this is actually copied out of our source code. This is the code for referencing a new tab to a new variable table to an old variable table. And literally, so we actually just have zero as a special key that stores the previous referencing environment, right? So basically what happens is that we massively abuse associative arrays, right? Which should either sound familiar to you guys or you guys are a lot more honorable than I am as a programmer, right? So we massively abuse associative arrays, but it's not too bad. When the code is clear and we comment properly, it's kind of maintainable, not great, but yeah, it kind of works. But we have used a framework probably not because this is not, there's no M and there's no V in this, it literally takes a piece of source code and it produces output and error messages and stuff, right? So probably we couldn't have really used something different. The downside of using naked PHP is that we literally build our own homebrewed auto tests, right? And that's not very nice. Maybe we could have found something that we could hack on even though we're not using an MVC framework, but I'm not sure if that actually works, but it's a thought. And one issue that we run into writing an interpreter like that is that we, so if you recall, this thing is actually a tool, a testing tool for our candidates, right? So what we want to be able to do is we want to be able to differentiate if the candidate writes efficient code or less efficient code. So if the candidate makes an ON square solution versus own solution, we want to know, right? But the problem is that because we're not exactly experts at the low levels of PHP and how fundamental PHP operations perform, we can't just time it. At least we won't trust that result if you just timed it, right? So, but because of the way we wrote it, what we did was we made an approximation because every time you execute a while block, for example, that's a recursive call to the execute function because it's a block and it goes to the execute function. And every time you call a recursive function as well, you will call execute. So we literally can just count the number of time execute this call and that gives us an idea of what the algorithmic complexity of the solution is. And it turns out that it works pretty well. So that's what we're rolling with currently and yeah, it's been working, okay. Random things we could do because we decided to roll our own print in the printer. We could do random stuff like disabled language features, right? We could, for example, there was once where we had a question. It's not there anymore so I can talk about it. We had a question where we tried to get people to write FISBUS, the classic problem, without if statements. And we can actually just disable if for that question and then if just doesn't work, will not work with the printer, right? So, but that did turn out to be a good question so we took it away but yeah, the possibility is there. We can also do stuff like compute, these metrics like cyclomatic complexity and similar stuff, what we're doing evaluating. And the idea we had originally was that we wanted to see whether any of, we could get a collection of metrics that would correlate well to the quality of the code that our candidates submitted but yeah, we got busy so we never really pursued that very much. But the data is still there so that's nice. And that's kind of the end. So if anybody, so this thing's still running, right? If anybody are interested in what we do, you can sign up at mocentral.com. You'll get to end up playing with this because you'll be asked to write some programming tasks in local M, right? So that's about it. Again, if you can come up to me, actually I can open the floor for questions now, right? Yeah, so if you have any questions, you can ask me now. Going back to your original presentation on... On mocentral, oops. It really makes it fair for the people that are doing contract work on software and things like that because they work an hour, they get paid for the hour and so on and it cuts out the creep and all that sort of stuff. My, I can see the challenge that you guys would have though, like with some of the clients because the clients are always trying to squeeze the programmers to get more out of them. So they might not actually like such a rigid system because they're used to being a villain to screwing the... Yeah, well, yeah, well. So in that department we do kind of have an uphill task in terms of convincing clients, but the thing about it is that we believe at least that the math adds up, you know? You're actually cutting hidden costs no matter what, right? So if we can get our guys to be consensus, we can teach our clients to make sure that they're on top of what they do, you will save money, you know? You will save money. We have clients who have basically proved to us that they save money. It's actually a job in educating the client of how to do their own... Yeah, but the consolation is that we're not selling any kind of fraud or anything. This is something real, we just need to show it, you know? So yeah, that's the challenge that we're working on. Yeah, so we don't accept clients who don't accept the terms right now. How long is this market placement going? Almost two years, I think? Yeah, almost two years. And before that we were the agency thing, the nightmare agency thing, yeah. Thank you. So, anything else? You guys must have had a lot of time to run the compiler. Well, actually, so I'm gonna plug Yee-Hun over there a bit. The agency freed up so much of your time that you guys get to do it. Yeah, because, you know, we had this idea, right? And then like we... University was still fresher back then, and then I took a course on problem language, so. So I had some idea of how to do it, right? And then along comes this Yee-Hun who's sitting over there, right, he happens to be here. So he was our star intern back in the day. He was still in school, but he was in the Malaysian Informatics Olympiad Squad. Yeah, so he came on as an intern and then we realized that this guy is really good with algorithms. So I just sat down with him and I told him, okay, this is how I do it, how I do it. And then he wrote out like vast swathes of what's there now, so yeah. We got that out. We got that out. It's cool. Yeah, so, so, yeah. I heard you started with two technical co-founders? Yeah, well. So in the sense that we both have technical background because we both used to be, in a short time, we both used to be on the ground slaving away on client projects, right? So yeah. Although I suppose the more technical co-founder would be me, so I'm usually in charge of the technical infrastructure and everything. My co-founder, Sue, and it's usually, like she's better with making slides. She doesn't hit her slides like that. So usually she'll be the one here talking to you guys, but she's not available today, right? So I'm kind of here too, yeah. So is that it? Do you have anything else? All right. OK, so thanks a lot. So yeah. Yeah.