Board: A Step Back For A Moment

In case it wasn’t obvious, I missed my goal date for the features I wanted — mainly multi-user logins, with the virtual tabletop working alongside that.  My date was keyed on when I needed the tools, which was Sunday.  Now, this wasn’t a disaster.

First, I had a backup plan – to use the original code I wrote and which worked well enough four weeks ago.  It’s always good to have a backup plan, because things happen — I got sick, and had a guest for a week, both of which ate into my development time.  This happens all the time; every job I’ve worked had some moment where the priorities of the business changed around the project, and the project had to change as a result.  Successful projects made the change; the ones that didn’t change weren’t successful.  I once had the business culture change enough that the project was no longer necessary, or at least 90% of it wasn’t.  Which meant it was costing the business to keep me employed working on it — so we transitioned the 10% to the approrpriate teams, and phased our project out of the workflow.  I consider that a success, because we did the right thing for the customer, even if I was looking for work at the end of it.

Secondly, the game wound up getting cancelled — which happens fairly often, but isn’t something you can plan.  I’ve had projects which were ‘saved’ by the customer just not having time to evaluate the code.  This certainly shifts the date out (and I had one ongoing project where my clients were so busy that they could only do one feature a month, no matter how big or small it was, so a slip like this could push everything out in increments of a month), but it’s something the customer understands.  Even if you have to shift a date out, making sure the customer understands and agrees keeps things successful.  No project plan lasts the course of a project, but it’s good to take a moment when things change and re-evaluate what’s going on.

And that’s what I’m taking some time to do today.  I’ve been using the YAML CSS project as the base of my design (this is different from the YAML markup language, which I may also use).   I noticed last week that I’d edited my templates down to where I wasn’t compliant with their license, and that they’d updated to a more flexible responsive layout.  I’d planned on dropping it after reading about more responsive flexible layouts, since it seemed to want to force me into two or three column layouts that didn’t feel natural.  As it is right now, http://board.cultoftheturtle.com/ doesn’t look that great because of the hacking I’ve put on it in the past four weeks.

This includes the user input section where some radio buttons seem odd, and there’s a bit of a mishmash of css around the whole thing.  I was working with that last week and just kind of threw my hands up — did I finish the user stuff so I could meet the deadline, or do I step back and fix the CSS now? I didn’t know the answer then, but today, after my deadline, it seems pretty clear that I need to fix my structure some, and get it ready for a decent design.

I’ll use the User pages — both the administrative and user-centric pages — as my test for the design before moving onto the boards themselves, with a hopefully cleaner css.  The virtual table really  needs a clean CSS design, as it depends on some positioning features, and anything that’s off or not quite right will make it harder to get it working.

So that’s the goals for the next couple of days.  I’ll have a post on Wednesday — all else going well — about how the whole login and signup process works, and then once that is done we’ll finally start talking about Games, Boards, and Tokens which the actual work of the site depends on.

Board: Logging in With Google

So, a bit behind on this which I’d hoped to have done last Wednesday, but head colds and real life wait for no one, particularly people who do development on their own time.  This pushes me up against my weekend deadline, but I have the old code to rely on, and, frankly, a little time pressure is a great way to get work done, eh?

A bit of research uncovers that while Google uses OAuth, it’s often limited to which service that you’re trying to access.  A bit more research shows that they also support OpenID, and in a way that meshes with their OAuth.  So, while I thought I’d be doing OAuth today, instead we’re going to work on OpenID.

The “Auth” in OAuth is actually more Authorize than Authenticate. For the boards app, I’m more concerned with Authenticate.  OpenID is only an Authentication method.  It does have a way to get some basic details about a person — a nickname, possibly an email, a few other tidbits, mainly about identity and the way people want to be seen.  There might even be a user icon, depending on the service.  That may matter more when we’re into Tokens, but it’s good to note now.

The same person who wrote the OAuth component for Cake also wrote one for OpenID.  OpenID is a bit more complicated than OAuth (for all that OAuth is perhaps a bit more secure, and supports doing more than just confirming identity.)  A good portion of this is that OpenID has had a chance to evolve, and can be (and has been) implemented by a lot of different people.  There’s signed and unsigned requests, two different ways to request information about the user (like their email or name), and within one of those ways there are multiple ways to make the request.  Typically only one of these ways is supported (if any are — and they aren’t required) so getting information back is tricky and not completely certain.

The only information you can really count on is a field called identity_url, which sits at the base understanding of what an OpenID is.  Basically, an OpenID is a URI which identifies a single person.  It’s like an email address in that way, really, and in fact, Google’s OpenID is based around your GMail account (or Google Apps mailing address).  It still returns a valid http URI, which uniquely identifes a user, and that’s good enough for us.

Using the cakebaker OpenID sample, I’ve got a method to allow for someone to enter their OpenID URL (which might not be the same as their identity_url), and log in using that information.  For Google, we already know the endpoint url, we’re using, and it builds the users’ identity_url for us, once that user logs in and agrees to our information request.  For now, we’re storing that url with the key ‘openid’ (just as for Twitter OAuth, we’re using ‘twitter’ and their user id that we got back from Twitter).

I again filled this in with my information and codes, and I’m logging in with Google.  The next piece will be what to do when someone who we don’t find in our database tries to log in.  We’ll want them to set up a new account, and for that we’ll want to grab a little bit of information from the auhentication provider, if we can.  That could be a username/nickname or an email,  and hopefully, a profile picture (which will allow us to set up a user token for the new person).   And we’ll need a way for them to modify this information, or provide the parts we don’t have so we can set things up.

 

Deeper into the JavaScript

In some ways this is a list of links to review again as I learn what I’m doing.

First is a StackExchange post about what everyone should know about Javascript.

That led me to the JavaScript Garden which has more information about quirks and best practices in JavaScript.

It also led me to this quiz that kangax wrote, showing with some simplicity some of the oddities of scope, syntax and so forth of JavaScript. I initially only got 4 right, although I’d probably have gotten a few more if I’d read and thought more carefully.  I went though the questions one by one, until I understood them, which is what this sort of quiz is for.

It took about an hour, a good part of which was reading kangax’s description of how delete works, and how the different scopes for global, function and eval work.  And I’m getting a clearer understanding of what happens in function declaration vs function expressions.  It’s also pretty clear that best practices have changed over the past few years as the products have matured and people’s understanding changes.

I’m thinking about the Meeting Room signs I wrote here for work, and how I wouldn’t release that code today.  They are working well and staying running, but the code is bad, potentially unsafe (not really as there are only 2-3 people who can enter text on the monitors) and I’d rather be proud of it.  Rewriting that for the new CakePHP platform here at work would be a good project while I wait on other things here.

Ooops I broke it

Looks like in the migration of moving here, and some time after I ran the one use of the boards for my hangout, I broke the boards that were working.  It looks like mainly it was when I moved from Boards and Token having a hasAndBelongsToMany relationship to a more complex “has Many Through” relationship.  So I kludged it together as a fix today, and realize I need to clean up that code.  Of course I’m working on the official part of that next week.  So, it’s still working now (important to keep it working), but it’s a bit of a mess.

I updated the about page with a bit of todo stuff, to keep track of what I’m working on and what tasks need doing.  Sometimes I think of things that just aren’t important right now, so now there’s a place to put that. I kind of wish I had a wiki for it, but I don’t want to stop and implement it today. Maybe in two weeks after the next time it has to be working.  I’m feeling some pressure to get my current todo list done by then.

That’s good, a little time pressure is a good thing for getting the creative juices flowing.

I’m also starting to let people know about this and see it (yes I’ve been blogging, but other than a whole lot of spammers, no one has really seen this yet.)  That’s good, and I’m getting some feedback.  Hopefully I’ll have some uses that aren’t people I’m interacting with directly, nothing better than user to find problems and promote getting things done.  Except time pressure, I guess. Both together is nice.

Boards: User Sign-on

Okay, this week we’re going to work on getting the ability to log into the board game server, as well as letting people register for new accounts.  For now, we’ll have two levels of user — admin and player.  The other thing I want to do is to let people use external services as their identity provider.  That means I’m not storing anyone’s password, and therefore can’t leak them.   That works for me, plus, it gives me a chance to play around with OAuth, OpenID an FacebookConnect.

Now, last week, the people at Failbetter Games posted this article on how they are no longer authenticating only to Twitter and Facebook, but also allowing a user’s email address to be their login id (which means they’re now going to store a password as well.    Their game is a social one of sorts, and therefore, in their mind at least, they have the “stigma” of social games.  Particularly where they post things to your various streams without your consent, or at least annoy your friends.  By offering another option, they distance themselves from that stigma, even if they still could do those things if they had your Twitter or Facebook authority.  It’s more about perception than reality — I’ve played their game and it only tweets on my behalf when I specifically ask it to.  Sometimes I get DMs from them, but I can stop that by unfollowing them, so they are already somewhat ethical.

It still made me think about my plans here.  I’m not offering this same option, at least not right now, so that’s a consideration. I have no interest in tweeting or posting on facebook for people, although I have to admit, I don’t know how the invite system is going to work in the long run. Having access to a list of people in someone’s social web might make that easier, if they’ve also selected to play the game.  Still, it’s not really a requirement, nor do I want it to be.  I’m also allowing OpenID as a way to log in, and that’s pretty flexible and not really tied to a social network.  (Anyone with a WordPress blog can offer OpenID for themselves, or all their users, for instance.)

So, I think this is good, but might be something to revisit in the future.  For now, we’re going to start by doing OAuth with Twitter, and getting my account logged in.  Then we’ll go through the plan for registering accounts and get that working.   Then, as the last part of it, we’ll do logins via Google, OpenID, and possibly FacebookConnect.  I’m leaving that one to last as it may be prohibitive in some way (I’ve not researched it at all, yet).

The plan for now, is two tables:  a user table that will join to everything else for the purposes of doing things in the system, and a logins table that will link the secret and identifying info we get back from our web-based authenticator. This will mean we’ll probably need a user profile editor that will let them associate other connectors with their account (and log in with any of them).  This would just get us even more options for lists of friends to offer games to, etc.  And more flexibility for our users.

There’s a decent cakePHP Oauth component to be found here. It has a basic guide for Twitter, although it’ll need changes.  The main change I made to their sample code was to go to api.twitter.com/oauth/authenticate instead of  api.twitter.com/oauth/authorize .  It doesn’t give me any right to tweet on my users’ behalf — but for now this is good.

I captured the information it got back when I personally logged in, and I filled the code into my users controller to log me in.   This needs to be moved into a special authentication component plugin for AuthComponent, but I want to wait until I’ve got another couple methods implemented, and know what can be refactored out.  It’s also time to start checking security on the pages, and make sure people are logged in before they can do anything.

That’s the next step.  Once that’s done, we’ve got a couple of options: Google Login (which I need for my Hangout) and user registration (ditto!).  I’ll talk in more detail about how those work (and cover how I’m doing OAuth with those pieces), the tutorial for twitter with the cakePHP component is pretty good and I don’t need to walk back through those steps.

More on Wednesday

Boards : Technology

So, let’s talk about technology.

We need a back-end, something to persist state and manage stuff on the webserver end.  I’ve thought some about using node.js, both to learn to use it, and because we’ll need to be writing rules about what kinds of moves players can make, by using JavaScript on the server side, it would mean we could write that code once. Otherwise, we’ll be writing the same logic in more than one language.

Unfortunately, I don’t control the server I’m using (I have a home linux server, but I want this on a more robust site than my home Internet).  That puts node.js out of my reach for now, but I’ll leave it as an option.  So instead of learning something new, I’ll go with something I’m comfortable with on the server, and that’s LAMP.  Since I don’t want this to be a big drain on my time, I’m also going to use CakePHP since it’s what I’m using at work, and getting more familiar with it just makes me better at work.

I don’t have any illusions that PHP is the best web programming language, or that Cake is necessarily the best library to use (or that I really need something as hefty as Cake for this project).  But what I do know is, that when I look at the skills of the programmers (aka: me), this is what they know the best.  I’ll be more productive this way, and until there’s some technology requirement to do something different, I’ll keep with it.  I suspect we may refactor away from cake at some point (and perhaps away from PHP), but for this beginning bit, I’m sticking with this as the backend.

The front end is HTML5 with JavaScript.   Why HTML5? Primarily because of Canvas.  I want to be able to support image composition and saving it into the database, and I know I can do this with Canvas.  That may come later (when we start letting players design maps, for instance) and there might be some other features we can leverage, since we can easily draw on canvas, etc.  This does limit the browsers, but my primary users are all on G+ which already requires HTML5, so that doesn’t limit us too much.

For JS, I’ll be using the jQuery library.  They’ve already got a lot of the animations, drag and drop functionality and other bits that will make this pretty easy.  I looked at a project called fabric.js which is a really nice canvas toolkit.  It has some bugs with it’s event system, mainly for things that are stacked on top of each other. It’s fixable (I’ve looked at it and think I might be able to do it.)

On the other hand, jQuery uses the dom to move things around, and I’m familiar with that already.  Again, this may be a temporary decision, and I may borrow some techniques from fabric as they’re needed.  The goal here is largely OSS while running a service, so I’ll release anything I make — so I figure a little borrowing is okay.

I’ve also got a html framework that works with html5, incorporates a good clearfix and tools which bring all the different browsers in line.  If I was going to support ie6, it’d work too.  I need to make sure that I’ve got links to it in my template, and clean the templates up a bit for this project, but it’s also freely available.

So that’s the technology we’re going to start with.   I need to get a todo list updated on the site, but on Monday we’ll start looking into how we’re going to handle users.  By this time next week, people should be able to log in.  In two weeks, there should be some basic VTT functionality as we work on phase 2.  That’s the plan anyway (and since I need it in two weeks, I better keep to the plan.)

Breaking It Into Shape

I’m having a conversation with some people about JavaScript.  A friend of mine is a veteran C++ coder, and is and  indie game developer working in that language.  He’s also learning JavaScript via codecademy.com. In some ways Codecademy is a bit oversimplified for us, as mature developers we can see through to where we’re going and skip steps to go there, but the learning process wants us to make a few obvious (to us, anyway) missteps in order to help justify the better way later.

I’m reminded of when I was trying to teach Algebra students in college.  I’d started my time as a math tutor teaching Calculus (which was a course or two behind where I was), but as time went on, the needs of the group I was working with moved more into the Basic Algebra area.  At the time, I wasn’t very good at it — I had trouble breaking down my thought processes into those basic blocks that the teacher required.  “Show all work” is an interesting directive, but it’s not very specific. If I can add three numbers, or do a factorization in my head, then what I’m showing is all my work, but it’s not enough for the teacher.  Plus, it didn’t help my students any when I could explain how I got to something.  {I think I’ve learned how to do this better in the 20+ years since then, but I have some empathy for those students I tried to help back then.}

That’s a bit of a digression from the online discussion, however. The discussion was about the OO properties of JavaScript.  Now, JavaScript is an object based language.  However, it doesn’t follow the typical OO model, with it’s inheritance, polymorphism, and other traits.  JavaScript uses object composition and prototypal inheritance instead.   It’s a functional language in the since that functions are an object type in JS (but not in the since that J or Haskell are functional languages — JS isn’t immutable, for example.)

Of course, you can do typical OO inheritance with JS.  the Dojo Toolkit does this.  They created a new function to inherit and extend classes. (IIRC it’s actually called extend in Dojo, I’ve also seen it called create in other libraries.)   If you are disciplined and use the function, you get behavior out of JS that mimics the way C++ or Java might work if they were loosely typed.

This was actually my original introduction to the language, and Dojo’s model spoke to me, as I’ve been working with OO languages for most of my career. (My first industry job was developing with PowerBuilder, for instance.)   As I’ve worked, I’ve moved more towards the lighter, more flexible jQuery. It seems to work more the way I need it to, particularly when I’m working with HTML– with jQuery I’m using a tool that fits with what I’m doing already; with Dojo, I’m using a tool that wants me to be working with its own paradigm.  The advantage of jQuery is that I can drop it and most of my apps will keep working.  They won’t be as nice or as responsive, but they’d still function — and that’s an important point.

I remember when I was first working with directX, writing a simple Concentration type game for my niece. One of the common questions on the directX mailing lists (this was a long time ago) was “How do I keep people from pressing Alt-Tab, and leaving my game?”  There were game-balance reasons to do this, at the time Ultima Online had a problem with people writing tools that could play the game for you — and to initialize those tools, you had to alt-tab out of the program and start them.  So by breaking alt-tab they could go back to the way games used to run pre-windows, as the only thing around with no game-breaking tools or processes running.

Of course, to break it back into the shape they were used to, they had to break Windows. So, very often, the response on the mailing lists was simply, “Don’t do that.”  Not that it deterred them, IIRC pressing Alt-tab wasn’t possible in early builds of EverQuest. There might have been one MMO that actually quit if you alt-tabbed.

In general, breaking something so it’ll work the way you want means you’ve got a bad technology fit to your design.  You either need to adapt to your technology by changing your design, or you need to change what technology you are using.  Some of the worst kludges and messed up, fragile code comes from not doing one of these things, and forcing these things to work together in ways they weren’t intended to.

I admit that while I’m pretty competent in JavaScript, I’m still learning how to work with the language. It’s like I’ve made it up the first couple flights of stairs — I can read and edit code; I can competently write code in the language.  And now I’m looking at the next flight which is a deeper understanding of how it works.  I’m sure there’s another stairwell after that, and so on.  You never stop learning.  But getting to grok how object composition and prototypal inheritance work at a fundamental level is my next stairway.

I think my boards project will really help with that, and it’s something I’m keeping in mind while I work on it.

 

 

Boards : Thinking About Phases

The first thing that is obvious from the description of our beginning goals for the board game project is that we’ll have players, and some players will be able to do some things, and some won’t.  So we need some sort of user management, which will let us determine who can do what actions.  It doesn’t need to be super-complicated, we probably only have 2 or 3 levels or roles — an administrator, a player and game host, or a game master.  Precisely what those roles mean may change based on the kind of game, but that’s what we’re looking at right now.

Players should be able to initiate games, and invite other players.  For checkers, someone would host the game, and the other player would be the opponent.  For the VTT, someone would create a map, add NPC tokens, and invite the people playing their game to view it.  From that, we can see that we need to be able to draw a map of some kind, and have tokens on it that will let people move them around on the board.

We’ll need to be able to validate moves, both that whomever is moving the token has the right to move the token — I can’t move my opponents pieces in checkers, for instance (unless maybe the ones I’ve captured.)  I have to make a legal move — I can’ t move onto the wrong color square in checkers, if I have a jump I must take it, for example. [Legality of moves isn’t part of our spec for the VTT, that will be handled socially, not in code.]

Finally, we’ve got a chat log that will let users type text at each other, and will let them make dice roles which are reflected in the chat. Dice rolling is pretty much specific to the VTT for now, but if we ever do backgammon or a game like Monopoly then we’ll need to have dice rolls.

So for me, I see four basic phases:

  1. Users and Security
  2. Basic display and token movement
  3. Chat and dice rolling
  4. Moves and rules checking
Which is to say, phase 2 will allow anyone to move any token, we won’t get to being specific about who moves what until phase 4.  That’s okay as my personal priority for now is the VTT.   But the truth is, after phase 2 we should be able to play checkers with someone who was willing to be socially polite.  That’s not crazy, since it’s how we do things in real life.  Of course, this is the Internet, so we’ll need to do phase 4 to be really done, but we should see results after phase 2.
It goes without saying that at the end of each phase the whole thing done so far should be working.  And yes, these phases aren’t simple.  My rule of thumb is that the less words you use to describe a feature the more code it takes to make that feature.
On Friday we’ll talk about technology and platform, and then next week we’ll work on how we’re going to do users, since I don’t want to use the typical username/password method.

What I Want: To Help People

A few years ago, I read in Zen and the Art of Making a Living something that I had missed, and which moved me greatly.  It was something that I knew on some level, but had never thought about, and which no one had ever told me. I’d been told about doing work you were good at, work that paid well, work that you liked.  People had talked about that job that actually makes you happy — usually in wistful, mystical tones.

But Zen and the Art of Making a Living mentioned something that was completely different. The suggestion there was not for a job that sounds fun (with the thought that it would make you happy) but rather for meaningful work.  Because it would make you content, and fulfilled, and through that to happiness.

For me, that’s always been about making a difference in people’s lives.  In some jobs that was harder to connect with in others.  In my current position, I consider part of my job to put the public’s money to the best use, using technology.  That matters to me, and fits within what I can affect.   That’s nice to think about, but what has really come to affect me is the ways in which technology can affect the quality of someone’s workday.

Good technology makes people’s lives easier.  There’s been research recently that all the little annoyances that we deal with every day actually affect us more profoundly than some large problems.  The main reason for this is that we dismiss them, or prioritize them lowly, but they still aggravate us.  We don’t steel ourselves against them like we would a larger, so they get in and they bother us.

The systems I maintain here are old, and often designed poorly.  They are often frustrating to deal with and in many ways incomprehensible.  Not just to some of our users who have little to no technical education, but to someone like me who has a good grasp on how technology interacts.  I can help people in two ways : training and aiding them — and validating them as people who have to deal with difficult software, not people who are “stupid” or “just don’t get tech.” In today’s ubiquitous computing, tech  needs to adapt to the needs of people, not the other way around.

And that’s the second way I can help.  I’ve worked hard to educate myself on better techniques and methods to make it easier and clearer to people how to use technology.  I cut out data entry as much as possible using good defaults.  I find ways to make the software understand what someone means, as opposed to punishing them for “doing it wrong.”  I’m still working on this — and it will probably never be truly done.  What good software is changes year to year, and it’s something to constantly learn and understand.

But when I can make someone’s job easier — which is good for them, it makes me feel good.  It has the added benefit of allowing the place I work to be more productive as that person can work on other tasks that are more central to their job function.  But what’s most important to me are those days when I’ve given someone tools to let them control their job more easily, to do their work less painfully and to feel good about themselves when I do it.

And that’s pretty awesome.

Board Game : Goals

Well, before we can start the project, we need to talk about what it’s going to do.  I have a good idea of what I want it to do at a high level, but I don’t have all the specific examples ready.  In fact, there are probably some design dead ends and new features I’ll think up as I go along.  The agile way to do that is via user stories, and I’ll be writing those as I get to them on the board game project site (which will also implement the design).

So for now, I want to talk about the ways I foresee using these applications, and high level ideas for what the user stories will be for these uses.  Now I’m fully aware that some of these stories aren’t small. In fact, my plan is to order some of these larger concepts in a sequence, and then break them down into smaller more doable pieces and more appropriate user stories.

In part, that’s because it’s a good way to work.  But it is also because I want to be able to regularly blog about the progress two-three times a week.  That means getting work done in small logical chunks every week so I can write about and use them in the next week.  And that sounds just right for agile.

There’s a lot I’d like to do with this, but for now I want to limit it to two basic bit of functionality.  There share some things, even though they may sound wildly different.  I’m okay with this, as it’ll focus me some on abstracting the code early on to handle both of these cases.

The first idea is the Virtual Table Top.  In this mode, there are several players who control one more more tokens on a board, moving them around the virtual board according to the rules of a role playing game, such as Dungeons & Dragons. One of the players has a privileged role, called game master. That player can control any of the tokens, not just the ones that belong to them, and can create and edit boards for all the players to use.  There is an are for the players to chat via text, including a way for them to make dice rolls, which the server will randomize and output.

The second idea is Classic Two-Player Board Games. While the project has as its end-goal to support a variety of real board games, for this first iteration, I only want to support more classic games, where the rules are clear and the pieces fairly standard and straightforward.  In fact, I’m only going to pick one, and that’s the game of Checkers. I have some intuition about this: checkers plays out on a square grid (more or less — only half the squares are actually legal);  Dungeons and Dragons and similar games also use a square grid (there are exceptions here as well, most notably hexagonal grids).  So in Checkers, there are two players, each controls up to 12 tokens.  Neither player here is privileged over the other, although one of them creates the game, and invites the other to play.  We’ll also want the game server to validate moves for Checkers; we’re not doing this with VTT as it’s incredibly complicated and system-dependent.  But Checkers is simple enough to manage, and this will give us a template for later games.

The last thing to talk about is what isn’t in here, because we need to know what we aren’t doing so that we can limit our scope.  This will require an internet connection, and human players.  We’re not going to do offline games, or games with machine opponents.  While we are doing chat, it will be only text based, and fairly limited.  Voice and video we’ll offload to someone else: Skype, or G+ hangouts, or whatever the players agree to.  We’re mainly offering chat to provide dice rolls and basic commentary on the board most players will be looking at, so it’s not primary to the application.

I do want to do a lot more with this in the long run, but I think I’ve cut off enough to chew on for now.  In the next post, I’ll talk about technology and start breaking this down into some phases.  As with any agile development, the code should work for as much of the development as possible, and at the end of every phase.  Some of these early phases will be fairly limited, but the goal is to always have a working board game project.  (Plus I’ll be actually using it, once or twice a month to run games: there’s incentive for you!)