What's up, everybody? This is Courtland from IndieHackers.com, where I talk to the founders of profitable internet businesses, and I try to get a sense of what their story is like, and what's going on behind the scenes, so that the rest of us can learn from their examples, and from their mistakes.
Today, I am here with Philippe Lehoux. Philippe, thanks for joining me on the podcast.
Hey, thanks a lot, Courtland, for having me.
The last time we talked was over a year ago. You did a text interview for Indie Hackers back in August of 2016. At that time, you were making $45,000 a month from ConferenceBadge.com, and you had just switched over to working on your new app, Missive.
I have to ask, 13 months later, how are things going with ConferenceBadge.com and with Missive? And do you in any way regret switching from one to the other?
Yeah, it's pretty interesting because every time I talk about my story, or the place I am right now, people say, "You're really fortunate," because most people want to start businesses, right? I started the project four years ago, now called ConferenceBadge.com, and it went successful pretty quick.
The thing is, I realized quite soon that the project was major. People liked it, and I didn't really want to spend more time adding more features. At the same time, my partners, which at the time, when I founded Conference Badge with them were actually working with me part-time. As soon as the project got successful, I just wanted to work more and more with them, and one way in which I actually started working with them was to kind of tell them, "We should just not working on something else, right?"
With Conference Badge, which could pay the bills, we could start to find other problems we were having, and start hacking around those. That's where Missive was born, and after three years now… Missive, it's a really ambitious project, but it's starting to grow now, and we're at a place where we're really satisfied with the product. What's funny is, when I talked to my co-founders, we've never been as motivated as we are today, because we see the value, and our customers are really liking the product.
We're really fortunate to have Conference Badge, which is still growing. We have one really awesome employee who's managing it, and then we can focus most of our energy in that new project.
How big is Conference Badge now? Because I know it was doing $45k a month a year ago.
Yeah, so Conference Badge right now, it's a seasonal business, right? Conferences happen mostly in autumn and spring. Summer is usually smaller months in terms of revenues, but right now, for next autumn, we're planning for around between $80,000 to $90,000, if it's going according to the plan.
Oh wow. So Conference Badge has been growing the entire time while you've been working on your new thing.
Yeah, but I must say, we didn't stop working on it. I mean, we are still providing what I consider to be like AAA customer support, and we're still listening to the small complaints, still things are a bit too rough in the product or not good enough. We're making really, really tiny improvements where the times we really feel like we can improve it. It's not like we just dumped the project and let it die, really. It's still being maintained daily by our employee, and we still from time to time invest a bit of time to fix some problems we find along the way.
So there's a very long and detailed history behind how you got to where you are today, and I think while that's true in the case of every entrepreneur, the difference with you is that the story is actually interesting all the way through, rather than just being interesting right at the end when you find success.
Looking back at your story, it seems like what you're really good at is taking one level of success, and using it as a springboard to reach an even higher level of success. Basically, you're just snowballing all of your wins and accumulating even bigger wins, which is hard for a lot of people to do. Because I think the normal way of being for most people is that, if you find something that works, you really put all your focus into just not losing it.
If somebody has a stable job that's paying them a healthy salary, or they have a company that's making $50k a month, usually the last thing they want to do is take a huge risk and move on to something new. But that seems kind of like the story of your entire life, and it's worked out very well for you.
Why don't we start at the beginning of your story, and walk through it, and see if we can gain some insights? Let me start by asking, what originally sparked your interest in tech and in business, and what are the first steps you took to become an entrepreneur?
I'm 33 years old now, so I was pretty much, I grew up with PC and the Internet, and my mother was a teacher, so we had a computer quite early on in my life. Obviously the first thing I started to do was just gaming, right? Like most kids. I was gaming until I was 14, 15 years old, and at some point, the Internet got bigger. I don't remember if at that time we had a high-speed Internet connection, but my mother started to actually do websites. One she did was for our family tree, genealogy, right? So she started building that website, and as a contentious kid, I kind of did laugh at her skill saying, "Mom, it's not good. It looks ugly," you know?
And she laughed, and she just then called me son. Obviously she's French, but she said, "Son, if you can do better, start working." I took her at her own word, and I just started creating a website. Actually, it's the first one ever created, basically, something that did really get success or make quite a lot of money. I just started to look on the Internet for free oldies games, you know? Legal games, but free games. I gathered all them inside one website. Obviously I'm French-Canadian, so I speak French, so the website was in French, and there was no other website doing that at that time, so I quickly gathered hundreds of visitors. At the time, Geocities of France was called .fr, just host games there.
It really grew slowly, slowly to a point where I had thousands of visitors a day, and I didn't really know what I was doing, right?
How did you decide to put together this website of free games? Because I was also playing a lot of video games as a kid, and making websites, and that idea never occurred to me. Was it something that you were just making for yourself, or did you figure that it would be really popular with other people, or was it something that you were doing to learn to code? What was motivating you?
I think I did it for myself. The funny thing is, I was a bit ashamed, right? Because the cool kids I knew doing websites were kind of doing websites for their Counterstrike clan, or Starcraft clan, and there I was, creating a website for really old games no one really cared about, at least for my inner circle of friends. I don't know. It's been a long time, so I can't really answer that, but it was just like available resources that I could gather, and gathered into the world. That's pretty much it, I think.
When did you notice that your website started picking up steam, and people were actually coming to visit?
 I think after a week or two, I had 10 to 20 visitors, and already at that time I was hooked. I wanted to post my link everywhere on the web, and trying to get, I don't remember the name, but there was a place where you were listed on that website, you would kind of skyrocket your search engine ranking. I really worked hard to get a link there, and it worked, and slowly I was linked across hundreds of websites because I would just literally spend all my time posting the links everywhere, and it actually worked.
Slowly, I just started to work on the website, making it look better, without really knowing what I was doing. Just that the resources in French were pretty rare at the time, so I kind of had to learn English as I go to actually learn how to do things. It's funny, because there were times you would see things on the website, and you would be like, "Oh my God, how can they do that? It's impossible. I have absolutely no idea." Then you would just leave, it would take six months, but at some point it would click, saying, "Oh, that's it. It's just like an image, and it's in a table, right?" Yes, it's magic, but at the end it's not that hard. You go through all those steps, and at some point you're becoming better.
 You just took the time, and it didn't matter to you if it was going to take six months for you to learn, and over the course of how many years were you working on this website?
At least 10 years.
Wow.
You know, the story is that it brought me a lot of money in the end, because I initially started with a cheap webpage, but at some point I learned ASP, and I was setting up my own servers, and making it more dynamic, add more content, and then switch to PHP. It really picked up a lot of traffic, you know? I think the biggest day I ever had was like 60,000 visitors.
That's huge.
That's a lot of people. I've never done something like that again, but it was a point in time where, if you were doing something new that was not available, everyone would go look at it. It was one of the first free games websites in French, and people were looking for that.
It's really interesting to look at the fact that building this website in French was so advantageous for you, because you're really taking advantage of all of the advantages of picking a niche. The basic idea here is you choose a target audience, and you build something that's so specific, and so good for them that it really would make no sense for them to ever choose a competing product. If you are a French-Canadian looking for free games and there's only one site that's in French, then that's the one you're going to go to. Then there's a whole another advantage as well, which is that if you pick a niche and you don't have that much competition, then you don't have to make as many risky decisions.
If you think about the opposite case, somebody who's in a market with a ton of composition, they're constantly thinking about how they can stand out and differentiate themselves, and do something new. If you're doing all these new, unproven things, there is a high chance that they're going to flop, whereas if you're in a niche and you don't have very much competition, you can just take an old, tried-and-true idea that you know is going to work, and go with that. I think you did it right.
Well, I did it right, but I didn't know I was doing it right. It was just a hobby for me, so it wasn't really about money. At first, I didn't even have any ads on the Internet. I didn't know you can make money, right?
How did you start making money, and how did you get to the point where you were reaching tens of thousands of visitors? Because I imagine that the strategies that you started out with as a 15-year-old, you eventually improved on, and got better at.
Yeah. At first, it's pretty simple, I think. I had some affiliate links to the website where people were loading, I don't know, it's probably spyware, but I would get a dollar for downloads and subscriptions. I was maybe making like 5 to 10 bucks a day early on, and at some point I experimented with ads, pay-per-click ads, and I just started to click on the ads myself, like any kids would do, and see, "Oh my God, I'm going to be rich. I'm already at $100, I just need to click on more ads, right?" I think it was a Canadian company, so they probably didn't have really big fraud protection tech at that time, so it took at least a month before they catch me.
Then obviously I never saw any of that money, because they banned me, but it was my first experience, and it taught me, "Okay, you need to play by the rules.  Then slowly, I was making a bit of money with affiliate links, but it wasn't that big. But at some point, as my interest in the project was fading, because I went to university, playing rugby, football, and I was not really that interested anymore, and didn't make that much money. My friend working at the bar was making more money than me. But then, Google Adsense was released, and I put it on the website, and instantly I switched from $10 a day to something like $300 a day.
Whoa.
That has completely changed the name of the game for me, because it was like, I'm not that proud about that project, but man, it's making me a lot of money now.
You were in college at this point. Did you consider making this your full-time job? Because I think most people in that situation would be like, "I don't need a job. If I'm making 300 bucks a day, let me just stick with this and try to increase it."
Yeah, obviously I didn't work anywhere else, but I didn't see that as a legitimate project or business that could grow. I was kind of always thinking it would just fold in a week, or in a year. It can't work, really. I can't be making money hosting free games on the Internet, right? It can't be possible. It wasn't a time where entrepreneurship was that big, at least in Canada. It wasn't like Silicon Valley today. Probably, if I had that success at that age today, it would be a completely different game, because people would advise me to do things, right? As of that time, my father was like, "Hey son, where is that money coming from? Really, it can't be possible. What are you doing? Are you sure it's legal?"
I was like, "Yes, it's legal." I remember, we even took advice, we paid a lot of money to get advice, because he feared that since I was in school, and wasn't paying taxes in Canada, the government would go back to me and asked me to pay it back. I was putting some cash in case in five years the government would come back and ask for further taxes, which of course I was like, "Dad, everyone is having Google Adsense. No people actually save money to pay the government. It's not a real thing. It won't happen." Of course, you actually need to do that. I was like, "Okay." I wasn't an entrepreneur at that time.  It wasn't something, I wasn't thinking about becoming an entrepreneur still at that point. It was just like, "Oh my God, I'll make a lot of money."
Yeah, it's fascinating how much our thought processes are shaped by the conversations going on around us, and what other people are talking about. If you don't hear anybody talking about making websites, and making money online as an indie hacker, then it totally makes sense that you wouldn't really consider that to be a legitimate career, or a path that you could follow. It just doesn't seem like a thing that people are doing. So, did you ever decide to get serious, and eventually turn this into a full-time job? If not, what did you decide to do?
Well, slowly I actually started to implement more features. It was 2004 now, and 2005, and all the Web 2.0 was starting to kick in. Now I could educate myself about entrepreneurship, and there were all those blogs about technology and entrepreneurship were exposing me to that world. At that point, I decided to build something on top of it, and since I wasn't considering myself as a programmer or a coder. I was just playing with things I didn't really know about. I thought, "I should hire someone," so I looked for a computer engineer from the university where I was studying, and I just asked him, "Do you want to work for me? We're just going to evolve that website, I'm going to pay you per hour, and it's going to be cool."
It was like, "Yeah, fine." That's awesome, right? I didn't really know about, I knew absolutely nothing about Rails and Django, I think were quite new at the time. I was like, "Yeah, why not? It sounds like a really great idea." I do remember that at one point I said, "Why don't you use Django if it looks so awesome?" He was like, "No, that's not in PHP. I want to do one." I was like, "Okay, that makes sense." And so it took like six months. He rebuilt the website, and the idea was to create something like Kongregate, so it was kind of the YouTube of Flash games. That was kind of my idea, and we released the website, and it just really crashed. It couldn't sustain the load of thousands of requests.
The guy's framework just wasn't good, huh?
It wasn't good. There was absolutely no cache. If you were listing 20 comments on the homepage, you would query the database not only for each user, but for each property of each user. One query for first name, one query for the last name, one query. Personally, I didn't really know about MySQL, things like that, so I was kind of a copy-paste, snippet of code guy at that time, so I couldn't define this myself at first, but that's really at the point where I realized, the thing is that because this website crashed for a couple of weeks. One so we were able to fix it, I lost all my ranking on Google, and at the time I was in between the third and the first rank if you were typing Jeu, which is game in Google.
This was massive, you know? I would have stuck with that ranking, just two or three years later, I would've probably been bought off for hundreds of thousands of dollars because there were all those massive gaming websites, surfing the wave of Web 2.0, and all those American companies trying to get into other languages. I would have been like a perfect target to be bought off, right? But I just lost it, because of my tech incompetence. That's really where I told myself now, it can be a serious business. It's your passion, you want to work on that now. You know it, but you need to educate yourself. You can't do tech if you don't speak the language, and that's really where I started to learn coding by myself.
At first, it wasn't a passion. It was mostly I want to create things, and learning those languages would allow me to create those things, but I slowly fell actually in love with the actual craft of coding.
I mentioned this earlier, but I think a lot of people get discouraged when they think about learning to code, or really learning to do anything, because it's so easy to just look around and see so many hundreds of people who are way better than you are at this thing already. And so you're starting from way back. People take that and say, "If I'm not ahead of the game, but I'm in fact this far behind, then why even start?" Did you deal with that at all, or were you just gung ho?
No, I deal with that a lot. The funny story is, my driving license, I got it like at 25, right? It was a bit of the same experience as when I was trying to learn to code. Since I didn't start, let's say coding, the normal path for me at that time would to be to go into computer engineering, right? Since I didn't go that way, I kind of felt like it wouldn't be attainable for me, because it was too late for me to choose that path. At that time, maybe stupidly, I didn't think it was possible for me to learn this by myself. I would just always pretend to be a programmer, since I would never have been through all those engineering courses, knowing the deep stack and everything, so I would just always pretend to be one.
It's the same thing with my driving lessons. I was just procrastinating. It was like, "Nah, I don't have it." I need it, but I'm just going to in six months, right? I feel like it's the same for a lot of people when they're trying to learn something new. They see the month thing instead of seeing like, the first step to learn something is really to just learn the few couple of simple things, simple concepts, and when you master them, you can experiment with them, right? Having fun with them. That's often what I tell people that asked me if they should learn to code, even if they're 26, 30 years old. I'm like, "Yes, but you need to have fun in the process. Don't start to code to build a billion dollar company, it won't happen."
Learn to code to build a small prototype. You're getting a website? Do the website yourself. It won't be that beautiful, but at least you would have some experience. You will know if you like it, if you're going to be able to sustain hundreds of hours of non-rewarding work, right? The first job is just to find your fun. Me, personally, after my website kind of crashed, and I didn't lose interest. I was still making between $150 and $200 a day, which is kind of awesome, right? But I just started to prototype small games, and experiment with physics, particles, things that were really rewarding.  To me, that was where I really got addicted to programming, was when I developed a small game where you could instantly see the magic behind it.
It's endless, the possibility you can actually achieve when you learn the craft of coding. That's really when I got hooked to it.
That's funny. You learned really to help your business out, so you wouldn't have to rely on other programmers who were writing, quite frankly, crappy code that was crashing your website, but your ambitions and your goals ended up getting hijacked by the process of learning to code itself, and so you decided to go into, it sounds like game development. What was your next step after you got better at coding?
Yes, absolutely. But the funny thing is that all of this happened, I got really interested in the indie games space, and for good reason. My background with my game website, I've always checked those games, right? At the time, most of the small prototypes were free, so I will put them on my website, and that's where I found out about the communities behind those games. So there were indie games forums where people would start to do challenges, and those challenges were in a game jam, right? You would have like 48 hours, it would be a team, and everyone on the forum would come up with a game related to that team.
To me, it was mind blowing. It was really something that talked to me, and I really wanted to be part of that, but I was really just a lurker. I wasn't really part of the community, but I was always there. Those lurkers you never know about, but they're always there, because every day they go to the forum and they read everything, but I don't know why. I never really participated, but I started doing those experiments just for myself, just to learn to code and still experiment. I really got hooked to it, and hooked to the vibe of that community. The idea that you could just, kind of in an artsy way, take your craft, your coding craft and experiment with ideas and concepts. Not just like games mechanics, 3D mainstream gaming mechanics, but really experiment.
What about if the game is all about just one button? How far can the game mechanics or the story of the games change, given that we all have that basic game mechanic where you just press one button, right? Like Flappy Bird is an example.  This was really fascinating to me, so I started to experiment on my own, and then at one point I finished university, and it was like I don't know what I want to do. I feel like I want to become a game programmer, I want to have a game to do, but I feel like I'm not the best one. I didn't study in engineering, so I don't have all the skills.
I want to meet people doing that, so maybe I could be the business guy, right? Since I've studied business management, and if I meet those, we can start a studio, and it would be awesome. At that point, I decided to actually meet those people, that the best way would be to organize a game jam in Québec city. That's my hometown, and to actually meet those guys. That's what the people say, you need to meet co-founders. You need to meet people with talent. To me, it was really great idea. I'm just going to create a massive game jam, where every single developer in Québec city will want to go, and it's going to be awesome.
That's so interesting, because it's kind of similar to your earlier idea, where you put up that free website for games, and this is something that had been done in other languages, but not in French. Here you are creating a game jam for your city, and it's not like this is the most original, unique idea that anyone has ever come up with. This is something that you already saw working, that was already exciting and getting a lot of people motivated, and you wanted to bring that to your own city. I think that's such a great way to go about it. The other thing that I think is so interesting, as well, is I think a lot of people who come on the Indie Hackers forum and ask about how they can expand their network, or people who email me and say, "I've reached out to all these people, but nobody is responding. Nobody wants to work with me, etc."
The common theme is that if it's difficult for you to expand your network and to meet the people that you want to meet, it's probably the case that you haven't really done anything impressive that shows that you're serious about it.
Yeah, exactly.
Whereas your situation, you immediately went into, "Let me actually do something. Let me create this giant game jam," which automatically makes you a pretty significant person who's worth getting to know.
Yeah, exactly. I think you need to bring meat to the game, right? You need to bring something to the table. You can't just expect people with talents and abilities to join you on nothing, right? You need to bring something to the table, and at that time I thought, "I could be the business person." Organizing the game jam could be a good way to prove to people that it would be great to start a game studio with that guy, because he organized that big thing. The thing is, the game jam was called the Bivouac, which was kind of the fire, and the idea was more than just a game jam. It was really a festival. There would be music, there would be art displays, there would be the game jam.
It would all be held outside, so the game jam would be in big tops, and it would be held downtown. We had that massive idea, to create that big event, and I did it with one of my best friends, who was at the time an event planner. It was really a good fit. I had the vision, he had the ability to manage the event, and then I managed the media, I raised the money, and he did all the technical stuff to make the event happen.
I was going to ask if you had no event experience, how did you do this? But it seems like you met the perfect person.
Yeah, it's one of my best friends. Really now in Québec, he's really one of the best to organize anything. He can pretty much do anything with any budget. If you ask him, he can make it happen, right? This is the kind of people you want to do business with. We were kind of two guys who would just go out and do things, and in a matter of five months, the first year, we met the mayor. I think I met really one big minister from the government. We had no prior experience, or no one knew us, but just by the sheer amount of work we put, sending a lot of emails talking about the idea. We reached a lot of people in the government, and the city hall, and they all agreed that it was a great idea.
Québec was trying to distance itself from Montréal as also a game development city. Ubisoft was there, Activision just bought Beenox, which was a big, independent studio. There were a couple of other big independent studios. Québec city had that game industry, so I was really, with that idea, a game jam might be not a novel idea now, or even then on the indie games forum, but to the general public it was crazy. It was a really awesome idea too. Let's create a game in 48 hours. It can't be possible, right? The idea is that we would bring the people from the public to actually, they could walk through the people coding their games during the 48 hours, and at the end they could actually play those games, and it would be part of the judge that judged the games.
It was a really tremendous success. We had press. I think I did a live interview at CBC through all of Canada, in French. All the networks were there, I'd go to all the radio shows talking about the event. It was a really good, big success, but at the end of the day, it was so much work, and I never really ended up meeting or creating these friendships with game developers during that time. It was really frustrating to me, because it felt like I just tapped into a really big train, but I couldn't really control it to my initial goals.
Right. Your entire point was to network with people, and you were not able to do the thing that you wanted to do. How big was the conference? Because you said it was a huge success, and I know you ended up doing this for a number of years. Did it grow from year to year, or was it like an immediate hit, and it stayed the same?
Well, of course financially it was always hard, that kind of event can't make you rich. We weren't actually paying ourselves any salary, which, the reason I say it's successful, is that we had support from everyone, from the city, to the government, to private businesses, to the game studios. Everyone kind of chipped in. Not a lot of money, but to make it happen, right? At the end, I think the last edition, we had a budget of like $200,000. To actually organize a game jam in Québec city, to me it's a huge success. It's not LA, it's not New York, it's a small city. We had like 300 participants creating games.
How did you eventually decide to move on from the conference, and start your next project?
The last year of that conference, I told my business partner that I didn't want to do it. I just didn't have the energy to do it, because I felt it wasn't in line with my own goals. I wanted to, and now it was really kind of becoming harder to start, with companies and businesses. I felt it was really more what I wanted to do. I was seeing friends doing it, and I was, of course, reading blogs, and reading about all the success, right? You want to join in, you want to be part of that, since you're an Internet kid. At that point, I told him I don't want to do it, but in the end he said, "What if I do most of the work, and you can just experiment with the event yourself, and actually create a game? You just need to deal with the media during the event, and you can actually build your own team, and be part of the event yourself."
I was like, "Well, that's a brilliant idea." Actually, I can kind of experiment with my own creation, so that's what I did. The funny story is that I actually ended up partnering with people that were working in my co-working space, and those guys are now my business partners for Conference Badge and Missive. It did end up working, right? But it wasn't the game industry. At the end of the day, it was mostly in the web technology, but I did end up actually not met, but at least created friendship relations during that event.
Okay, so what did you end up doing after the event was over?
After the event, I was thinking about, "What can I do?" That's always the question. At that time, my gaming portal wasn't making any money anymore, because with iOS, it was kind of the end of the Flash game era, or free game era on the Internet. Everybody was playing with iPad games or iPhone games, so I wasn't making any more money. I was thinking that I needed to come up with an idea that could actually help me to pay the bills. I was juggling with a lot of different ideas, and one day I kind of stumbled on my friend, one of my best friends, the one who organized the Bivouac with me. He was in his apartment with his business partner, so they were actually now a real event organizing company.
They were kind of printing name badges, using a real old Windows program that they said they paid $500 for. I was like, "What?  Really? It looks that ugly." At that time I remembered, I helped them do it, and then I remembered how painful it was for us, a few hours before each edition of the Bivouac to actually print the name badges because you need to deal with last-minute attendees, and the templates never really work. It's always complicated, and you have no time for it. I said, "That's it. I'm going to build a name badge in a tool." It's a totally unsexy idea, right? Nowadays, it seems really cool, because it's making money, but at this time my friends were like, "Really? Build a name badge tool? That sounds strange, but okay."
And so I just started to develop it using the Eventbrite API, and then I quickly realized that although I had the skills to build the JavaScript editor to build your name badge template online and then generate the PDF with it, I think I lacked some design skills, so I asked my people who actually did the Bivouac last edition with me to actually join me and form a partnership.
These are people from your co-working space?
Exactly. This was all happening at the co-working space, which I actually founded. Yeah, we started working on it, and after like five months, just a few weeks before we released the app, we received an email from Mitch Colleran at Eventbrite, and he's asking us, "Are you?" I think if I quote him literally, it was like, "Are you doing what I think you're doing?" Because he saw our app name when we were querying the API at Eventbrite, and I was like, "Yeah, we're building a name badge tool." He said, "Oh, I need to call you," so I set up the call and he was like, "This is awesome. It's the most painful thing our users face, and our engineering team has no time to deal with this aspect of the product.
We were like, "Whoa, okay." Part of our success was really to build the product around an ecosystem, and to bring value to that ecosystem. That's really where I see the initial reason why we have success that fast, just because we provided value to Eventbrite. You know, what's funny is that they never asked for money or a commission. People always ask us, "How much money do you give Eventbrite?" We don't. We provide value to them. People now, it's one more reason to use Eventbrite. When you use Eventbrite, you pay fees, right? They don't care if on top of that, they give us money because we manage their name badge, but their solution now has more value.
Yeah, it's a win-win for everybody involved. Did you have a plan for how you were going to find customers and distribute your product before you talked to Eventbrite? Because at this point, this is really your third big project that you've worked on.  What kind of lessons did you take from those earlier successes, and how did you bring those into Conference Badge?
The reality is I did a lot of different things before that didn't work, that I just didn't talk about then. My game portal, I launched it in many languages and never had more than two visitors. I started software businesses, too. I started a lot of things that never really went nowhere before that, but no, I had absolutely no plan on how to promote Conference Badge when I was developing it. Most people will tell you, if you build something right, people won't come, right? In a sense, it's not what happened with me. I was never really a good marketer. I'm not that good to tell stories. I'm not a teacher, so I'm not the best one to talk about the value of something. I get lost in my own words.
It was really always about focusing on building something great, and it's probably luck, in some sense, but of course my successes are not massive successes. They are still small-scale successes, right? That's probably the difference. Of course, if you build something great, some people will show up. Maybe you want to become as big as possible, but I must say I never really focused on that. It was really about building something that worked, and every time we had a customer, we were giving him AAA service. If he was having some technical problems, we wouldn't go to sleep until it was fixed. If someone had a conference, and you wanted last minute badges with QR code and we didn't have that feature, we would not sleep until it was shipped because that guy needed it, and we didn't want to let him down.
It was really about nurturing the few customers we had. Then I think it's just word of mouth, plus Eventbrite. But now Eventbrite is like 35% of our traffic, and we never really advertised this solution, so I think it's really word of mouth that comes into play. People use the product and are like, "It saves me a lot of time." Because some people on roadshows, doing events every week, they lose so much time printing badges just hours before the event. Now it's all cooked in, baked in. They just need to order, and that's it. They reuse the same template, they import the attendee list from Eventbrite. They would pay, I think some would pay 10 times the price they're paying now, because it brings so much value to them.
I think it's very interesting what you talking about, because you did almost all of the perfectly right things in order to spark word-of-mouth growth, and you have this belief that, a lot of people think, "Okay, if you build it, they will come." Which is often railed against. You need to actually have a marketing plan, but to some degree, it can be true, in the form that word-of-mouth grows if you do the right things. If you're targeting a specific niche, or all of your customers tend to hang out in the same place, like Eventbrite, or all the conference organizers know each other, or they're on Meetup.com or something, then your product is a lot more likely to be able to spread via word-of-mouth because those people actually talk to each other.
Versus if you have a product that targets people who are teachers, and construction workers, and professors, they don't really talk to each other, so it's really hard to spread.
Right.
On top of that, you guys built this great product that solved a pre-existing problem. If you can build something that really solves a problem, then people might just find you on their own. If people are already hosting conferences, then you know what? They're Googling name badges, and they're going to look at the options and pick the best one.
Yeah, and what's interesting is that although I said this with Conference Badge, that I had no marketing plans, with Missive, on the other end, it's kind of a completely different space. The problem is not that obvious. It's a generic problem. It's a generic app to actually manage your team communications. It isn't like, people are not looking for that, right? The interesting story, I think, is that now we are morphing ourselves to more marketers, because that's the only way you can really grow a business like Missive. You need people to talk about it, right? You need to find a creative way to make people talk about it, because even if it's great, if you want a spark, of course our goal is we do have virality in some real smart growth.
But the reality is that if you want to spark that initially, you still need to improve your marketing skills.
Just for some context, can you describe to everybody what Missive is, and how you ended up deciding to stop working on Conference Badge, at least as much as you were, and to start working on Missive?
Yeah, okay. The answer is the same story. As we grew Conference Badge, it with like a part-time partnership with my co-founders, and at some point we were making enough money to work full-time on Conference Badge or something, right? As creative guy types, people who were like, "Let's work full-time, pay ourselves with Conference Badge, but leave the door open to explore other problems or opportunities," right? Just try to come up with something else that might be, to us, more interesting to work on, or just to keep us interested in our work. At that time, Conference Badge started to grow, and we were dealing with a lot of customer support, emails from Eventbrite's partners, and our daily life was mostly in our email client.
Then we started to use something like, at this point it was HipChat, but today you would probably use Slack. That chat app, a lot was happening. We were chatting about how we should implement features, we were chatting about some of our customers requests. We were chatting about emails received from Eventbrite, who wanted us to deal with something, and it ended up, what we found out as we ended up with two big, massive silos of communication. We just felt, well, that might be a place and an opportunity where we can actually bring some value. What if we were to merge back those two silos together? The idea behind Missive is it's an email client. It's a really powerful email client, okay? It does everything you would expect from an email client. It gets news, it , it does all those things.
But instead of having email traits, you get a conversation. Conversations can become further emails, or chat messages, or a mix of both. It's a really generic app, okay? It's a team communication app that merged email and chat, but it really can help you deal with a lot of scenarios like customer support. You don't really need the mail desk when you work in Missive, because you can actually collaborate around emails received from customers. You can draft replies together with your teammates, right? The chat app, in Missive, it's straight up conversation, so you can scope your topics. You can use the powerful tools from the email clients, like you can snooze a chat conversation. You can create a task in your check conversation like, "pay taxes" and snooze it in 31 days.
In 31 days, then you can type, "Hey guys, I just paid the taxes," and it brought all of those possibilities to our daily workflows. As we developed it, we realized we really like that problem, and we really like the solution we came up with. The more we were working on it, the less we were working on Conference Badge, and it was clear for us at some point that it would be our main activity. Missive became our main activity, and it wasn't instantly we switched, but now it's like 95% of our work is Missive.
It's so fascinating and it's, I think much more clear to me what we were talking about earlier, which is that you really have to kickstart an idea like Missive to get it to grow. If you look at Conference Badge, it has a whole bunch of factors working in its favor. It was targeting a problem that already existed, and so people were already searching for the solution. In your solution to the problem, although it was well-designed, was also super simple and straightforward, and easy to understand. You guys also were targeting a niche in which everybody is kind of related. These are all event organizers, so they talk to each other, and make recommendations. Therefore, your product can grow via word-of-mouth.
They also hang out in single hubs like Eventbrite, so you can reach large numbers of your customers all at once. Missive, on the other hand, is missing a couple, if not all of those factors. I mean, you're doing something completely new here, so people are not necessarily searching for, "I need a collaborative email out of there so I can draft replies at the same time as my coworkers." They don't even know that they want something like that, so I guess you have to go out of your way to educate them, and teach them that this is a possibility that exists and can make their lives better before you can even make the sale.
Yeah, exactly. Something we found out is most product in that space, really successful product like BaseCamp, Slack, Asana, every single founder of those companies had fame, either fame or previous massive success, right? Slack is the guy behind Flickr. BaseCamp has podcasts, books, he built rails, so he has this massive followership. It's the same, if you look at all those successful business apps, they kind of use their own followers to boost their own business. Which is not something we have, right? So when you're facing something initial like that, you need to look. What are your own advantages? I don't have a big audience. It's a generic product, but I do know that there is a lot of value, because I experimented and believe strongly in it, and there is nowhere we're going to stop. It's the same for the three founders.
So what we told ourselves is like, let's take the couple of inbound leads we have every week, right? Let's talk with them, one-on-one. Book a call every time, and let's talk with them. See what's missing in the product, what the value could they get? Why are they interested in Missive in the first place? Having those conversations for now a year and a half, it changed a bit the course of the development roadmap, right? Each time we listened to a customer, and we dropped some more value to them, it really changed the growth curve of Missive. It was like if people, because when we launched initially, we had a big spurt of a few thousand people look into it but never really stick to the product.
Now, every time we launch new features, we actually know a lot of people actually want this. By listening to what the people who were interested in Missive, even if it wasn't big, if no famous person was saying, "It's the way to actually manage your business, use Missive," they were still interested and wanted to know why, and what was preventing them from switching. By listening to them, this is our advantage, right? We're passionate, I think we're a good product. We're good at making good-looking and productive products, so we took this advice, we talked a lot with them, and then we invested all our time in improving the solution.  Of course, we're trying to improve our marketing skills, but still I don't know.

At the very least, you guys can be sure that you're solving a problem that at least some people have, because you had this problem. You're really just scratching your own itch here, which means that you can easily test it and see, "Okay, did this make my life better?" That doesn't necessarily mean that everyone else has the same problem that you did, or that they want the same solution that you want and the way that you guys want it, but at least you're starting off on the right foot. You're starting off on a good place, and you can build from where you are.
But I must say that now we're at the place where we do have really interesting revenue with Missive, so it was like six months ago, it was still a big leap of faith, but now it's like, we're well-suited, you know? We know people are willing to pay, and it's just, do we need to scale this?
How much would you say that you really had to change the product itself, to get it from where you started to a point where it was really gaining traction, and you guys had a lot more confidence?
I think we realized that people, we were saying Missive is a mashup between an email client and a chat application, and the thing that was missing was, people find it really great. They were telling us, "That's cool, but I still end up, my email is mostly my task list. I do so many things, and it would be really interesting in Missive if that task list, those emails are not just tasked for myself. A lot of time, it's tasks related to my coworkers, right? So the ability to chat around those is nice, but it would be cool if I got some more guidance. If I could assign a conversation to someone, or create a task, an inline task in the comments of an email conversation, and assign this to someone," so when we wrapped the consumptive assignment in Missive, it really completely changed the conversation with customers.
When we introduced this, people were like, "Okay, now I will definitely try it out with my team." The difficulty with a product like Missive is, obviously you don't need to convince just one person. You need to convince everyone in the team, and that's the hard part. I think I remember reading an interview from the Slack founder, and he said the same thing. Obviously he had a lot of success doing it, but he said "The hardest part is you need to convince everyone that this is a perfect fit for their team."
What are your goals with Missive in the long term? Because unlike Conference Badge, and unlike a free game site, and even your game jams, this really seems like something that has the potential to have a lot more reach. Pretty much everybody uses email, and if you can build a better email client, then that's a lot of potential users. Are you guys considering raising money to try to grow faster, or do you just want to bootstrap it and get a small slice of a huge pie? What are you optimizing for, in terms of the outcome?
I don't have a long-term plan. I never really did any plan in anything I did, so I don't have a long-term plan. I do see the value of VC money if you already have traction, and you need to scale a winning recipe, right? Which I think we still have yet to, we're not yet at that moment. I don't think I would be interested in a discussion with VC at the moment, but if we do reach a point where it's I winning recipe, and it's clearly laid out, and you just need to put money on top of it to make it grow, why not? But at the moment, it's continuing what we're doing to get to a point where it reaches potential, because I do have those calls with my customers, and they really are enthusiastic about the product. It's really our goal to put the product in more hands, so that would be the short-term goals. But long-term goals? Why not? Making as big as possible.
We're getting close to the end of our hour here, but to wrap things up, it's been really interesting looking at all of your successes over the years. I know we've skipped over a lot of failures, maybe we'll have to do another episode and talk about those as well, but I think there is probably more to be learned from the successes, because you're really good at, every industry that you were in, taking a look at what was working, and what was broken, and building something even bigger off of the back of that.
Then you got into the event space because of that, and you were able to find out, okay, here's what's broken with events, and here's this massive opportunity to create ConferenceBadge.com and really make a lot of money helping people solve this terrible problem that you yourself had. Then as you continued working with your team, it became apparent to you that email is really broken for your use case, and it didn't support collaboration really well, and so you ended up coming up with the idea for Missive. What are your tips for people who aren't as good as you are at coming up with ideas for themselves to work on? How can they use their experiences to look at the world around them like you have, and identify the problems that are worth solving?
I would say do try to have fun in what you're doing. Sometimes being too serious, it's hard to make it in the long term. Lowering expenses, I saved a lot of money, which enabled me after University to experiment a lot with either code, or the Bivouac. I experimented for two years because of the money I saved. I never really spent any money on big things.
You know, that's really interesting, because saving money is something that I don't think we talk about enough, but it's really good advice, because what it ends up doing is it takes pressure off of yourself to have to succeed in the short term. Which is not only stressful, and no fun, but it also compromises your judgment, and prevents you from really being able to experiment and take the time to build something that people will find valuable.
Yeah. I think that's actually really good, what you just said. You're pretty good at summarizing other people's thoughts. Don't put too much pressure on yourself, actually, either financially or emotionally, because it's hard to deal with the pain of not feeling you're successful, and seeing people around you having success. Lower the pressure. Keep a good mental state, and experiment. That's what I did, and that's what I always do, is experiment. Try things, either with code or your life. That's pretty much it.
All right. I think that is a great new to end on, and I had a really good time talking to you. Can you tell listeners where they can go to find out more about you personally, and about the things you're working on like Conference Badge and Missive?
Yeah, I don't tweet a lot, but you can follow me on Twitter @PLehoux. Or else, it's MissiveApp.com and ConferenceBadge.com.
All right, thanks Philippe.
It was good to talk.
If you enjoyed listening to this conversation, and you're looking for a way to support the Indie Hackers podcast, then you should subscribe on iTunes and leave a quick rating and a review. It only takes about 30 seconds, but it actually really helps get the word out, and I would personally appreciate it very much.
In addition, if you are running an Internet business, or if it's something that you would like to do in the future, you should join me and a whole bunch of other Internet entrepreneurs on the IndieHackers.com forum. It's basically a community of like-minded individuals just giving each other feedback, and helping out with ideas, and landing pages, and marketing, and growth, and other Internet business related topics. That's www.IndieHackers.com/forum. Hope to see you guys there.


Class: ActiveSupport::Cache::MemCacheStore
| Relationships & Source Files | |
| Namespace Children | |
|
Modules:
| |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
Store
|
|
|
Instance Chain:
|
|
| Inherits: |
ActiveSupport::Cache::Store
|
| Defined in: | activesupport/lib/active_support/cache/mem_cache_store.rb |
Overview
Memcached Cache Store
A cache store implementation which stores data in Memcached: memcached.org
This is currently the most popular cache store for production websites.
Special features:
-
Clustering and load balancing. One can specify multiple memcached servers, and MemCacheStore will load balance between all available servers.
MemCacheStore
implements the Strategy::LocalCache
strategy which implements an in-memory cache inside of a block.
Constant Summary
-
ESCAPE_KEY_CHARS =
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 85/[\x00-\x20%\x7F-\xFF]/n
-
KEY_MAX_SIZE =
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 84250
-
OVERRIDDEN_OPTIONS =
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 35
These options represent behavior overridden by this implementation and should not be allowed to get down to the Dalli client
UNIVERSAL_OPTIONS
Store
- Inherited
Class Attribute Summary
-
.supports_cache_versioning? ⇒ Boolean
readonly
Advertise cache versioning support.
Store
- Inherited
Class Method Summary
-
.new(*addresses) ⇒ MemCacheStore
constructor
Creates a new
MemCacheStore
object, with the given memcached server addresses. -
.build_mem_cache(*addresses)
Internal use only
Creates a new
Dalli::Client
instance with specified addresses and options.
Store
- Inherited
| .new | Creates a new cache. |
| .retrieve_pool_options |
Instance Attribute Summary
Store
- Inherited
Instance Method Summary
-
#clear(options = nil)
Clear the entire cache on all memcached servers.
-
#decrement(name, amount = 1, options = nil)
Decrement a cached integer value using the memcached decr atomic operator.
-
#increment(name, amount = 1, options = nil)
Increment a cached integer value using the memcached incr atomic operator.
- #inspect
-
#stats
Get the statistics from the memcached servers.
-
#write(name, value, options = nil)
Behaves the same as Store#write, but supports additional options specific to memcached.
- #default_serializer private
-
#delete_entry(key, **options)
private
Delete an entry from the cache.
- #deserialize_entry(payload, raw: false) private
-
#normalize_key(key, options)
private
Memcache keys are binaries.
-
#read_entry(key, **options)
private
Read an entry from the cache.
-
#read_multi_entries(names, **options)
private
Reads multiple entries from the cache implementation.
- #read_serialized_entry(key, **options) private
- #rescue_error_with(fallback) private
- #serialize_entry(entry, raw: false, **options) private
-
#write_entry(key, entry, **options)
private
Write an entry to the cache.
- #write_serialized_entry(key, payload, **options) private
DupLocalCache
- Included
Strategy::LocalCache
- Included
| #middleware | Middleware class can be inserted as a |
| #with_local_cache | Use a local cache for the duration of block. |
| #bypass_local_cache, #delete_entry, #local_cache, #local_cache_key, #read_multi_entries, #read_serialized_entry, #use_temporary_local_cache, #write_cache_value, #write_serialized_entry, #cleanup, #clear, #decrement, #delete_matched, #increment |
Store
- Inherited
| #cleanup | Cleans up the cache by removing expired entries. |
| #clear | Clears the entire cache. |
| #decrement | Decrements an integer value in the cache. |
| #delete | Deletes an entry in the cache. |
| #delete_matched | Deletes all entries with keys matching the pattern. |
| #delete_multi | Deletes multiple entries in the cache. |
| #exist? | Returns |
| #fetch | Fetches data from the cache, using the given key. |
| #fetch_multi | Fetches data from the cache, using the given keys. |
| #increment | Increments an integer value in the cache. |
| #mute | Silences the logger within a block. |
| #read | Reads data from the cache, using the given key. |
| #read_multi | Reads multiple values at once from the cache. |
| #silence, | |
| #silence! | Silences the logger. |
| #write | Writes the value to the cache with the key. |
| #write_multi |
|
| #_instrument, #default_serializer, | |
| #delete_entry | Deletes an entry from the cache implementation. |
| #delete_multi_entries | Deletes multiples entries in the cache implementation. |
| #deserialize_entry, | |
| #expanded_key | Expands key to be a consistent string value. |
| #expanded_version, #get_entry_value, #handle_expired_entry, #handle_invalid_expires_in, #instrument, #instrument_multi, | |
| #key_matcher | Adds the namespace defined in the options to a pattern designed to match keys. |
| #merged_options | Merges the default options with ones specific to a method call. |
| #namespace_key | Prefix the key with a namespace string: |
| #normalize_key | Expands and namespaces the cache key. |
| #normalize_options | Normalize aliased options to their canonical form. |
| #normalize_version, | |
| #read_entry | Reads an entry from the cache implementation. |
| #read_multi_entries | Reads multiple entries from the cache implementation. |
| #save_block_result_to_cache, #serialize_entry, #validate_options, | |
| #write_entry | Writes an entry to the cache implementation. |
| #write_multi_entries | Writes multiple entries to the cache implementation. |
| #new_entry |
Constructor Details
.new(*addresses) ⇒ MemCacheStore
Creates a new MemCacheStore
object, with the given memcached server addresses. Each address is either a host name, or a host-with-port string in the form of “host_name:port”. For example:
ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
If no addresses are provided, but ENV['MEMCACHE_SERVERS']
is defined, it will be used instead. Otherwise, MemCacheStore
will connect to localhost:11211 (the default memcached port). Passing a Dalli::Client
instance is deprecated and will be removed. Please pass an address instead.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 118
def initialize(*addresses) addresses = addresses.flatten = addresses. if .key?(:cache_nils) [:skip_nil] = ! .delete(:cache_nils) end super( ) unless [String, Dalli::Client, NilClass].include?(addresses.first.class) raise ArgumentError, "First argument must be an empty array, address, or array of addresses." end if addresses.first.is_a?(Dalli::Client) ActiveSupport.deprecator.warn(<<~MSG) Initializing MemCacheStore with a Dalli::Client is deprecated and will be removed in Rails 7.2. Use memcached server addresses instead. MSG @data = addresses.first else @mem_cache_options = .dup # The value "compress: false" prevents duplicate compression within Dalli. @mem_cache_options[:compress] = false (OVERRIDDEN_OPTIONS - %i(compress)).each { |name| @mem_cache_options.delete(name) } @data = self.class.build_mem_cache(*(addresses + [@mem_cache_options])) end end
Class Attribute Details
.supports_cache_versioning? ⇒ Boolean
(readonly)
Advertise cache versioning support.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 38
def self.supports_cache_versioning? true end
Class Method Details
.build_mem_cache(*addresses)
Creates a new Dalli::Client
instance with specified addresses and options. If no addresses are provided, we give nil to Dalli::Client
, so it uses its fallbacks:
-
ENV (if defined)
-
“<IP_ADDRESS>:11211” (otherwise)
ActiveSupport::Cache::MemCacheStore.build_mem_cache
# => #<Dalli::Client:0x007f98a47d2028 @servers=["<IP_ADDRESS>:11211"], @options={}, @ring=nil>
ActiveSupport::Cache::MemCacheStore.build_mem_cache(‘localhost:10290’)
# => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 96
def self.build_mem_cache(*addresses) # :nodoc: addresses = addresses.flatten = addresses. addresses = nil if addresses.compact.empty? = ( ) if ConnectionPool.new( ) { Dalli::Client.new(addresses, .merge(threadsafe: false)) } else Dalli::Client.new(addresses, ) end end
Instance Method Details
#clear(options = nil)
Clear the entire cache on all memcached servers. This method should be used with care when shared cache is being used.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 215
def clear( = nil) rescue_error_with(nil) { @data.with { |c| c.flush_all } } end
#decrement(name, amount = 1, options = nil)
Decrement a cached integer value using the memcached decr atomic operator. Returns the updated value.
If the key is unset or has expired, it will be set to 0. Memcached does not support negative counters.
cache.decrement("foo") # => 0
To set a specific value, call #write passing raw: true
:
cache.write("baz", 5, raw: true)
cache.decrement("baz") # => 4
Decrementing a non-numeric value, or a value written without raw: true
, will fail and return nil
.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 204
def decrement(name, amount = 1, = nil) = ( ) instrument(:decrement, name, amount: amount) do rescue_error_with nil do @data.with { |c| c.decr(normalize_key(name, ), amount, [:expires_in], 0) } end end end
#default_serializer (private)
[ GitHub ]# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 225
def default_serializer if Cache.format_version == 6.1 ActiveSupport.deprecator.warn <<~EOM Support for `config.active_support.cache_format_version = 6.1` has been deprecated and will be removed in Rails 7.2. Check the Rails upgrade guide at https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#new-activesupport-cache-serialization-format for more information on how to upgrade. EOM Cache::SerializerWithFallback[:passthrough] else super end end
#delete_entry(key, **options) (private)
Delete an entry from the cache.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 288
def delete_entry(key, ** ) rescue_error_with(false) { @data.with { |c| c.delete(key) } } end
#deserialize_entry(payload, raw: false) (private)
[ GitHub ]#increment(name, amount = 1, options = nil)
Increment a cached integer value using the memcached incr atomic operator. Returns the updated value.
If the key is unset or has expired, it will be set to amount
:
cache.increment("foo") # => 1
cache.increment("bar", 100) # => 100
To set a specific value, call #write passing raw: true
:
cache.write("baz", 5, raw: true)
cache.increment("baz") # => 6
Incrementing a non-numeric value, or a value written without raw: true
, will fail and return nil
.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 180
def increment(name, amount = 1, = nil) = ( ) instrument(:increment, name, amount: amount) do rescue_error_with nil do @data.with { |c| c.incr(normalize_key(name, ), amount, [:expires_in], amount) } end end end
#inspect
[ GitHub ]# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 144
def inspect instance = @data || @mem_cache_options "#<#{self.class} options=#{ .inspect} mem_cache=#{instance.inspect}>" end
#normalize_key(key, options) (private)
Memcache keys are binaries. So we need to force their encoding to binary before applying the regular expression to ensure we are escaping all characters properly.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 303
def normalize_key(key, ) key = super if key key = key.dup.force_encoding(Encoding::ASCII_8BIT) key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" } if key.size > KEY_MAX_SIZE key_separator = ":hash:" key_hash = ActiveSupport::Digest.hexdigest(key) key_trim_size = KEY_MAX_SIZE - key_separator.size - key_hash.size key = "#{key[0, key_trim_size]}#{key_separator}#{key_hash}" end end key end
#read_entry(key, **options) (private)
Read an entry from the cache.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 240
def read_entry(key, ** ) deserialize_entry(read_serialized_entry(key, ** ), ** ) end
#read_multi_entries(names, **options) (private)
Reads multiple entries from the cache implementation.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 270
def read_multi_entries(names, ** ) keys_to_names = names.index_by { |name| normalize_key(name, ) } raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) } values = {} raw_values.each do |key, value| entry = deserialize_entry(value, raw: [:raw]) unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], )) values[keys_to_names[key]] = entry.value end end values end
#read_serialized_entry(key, **options) (private)
[ GitHub ]# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 244
def read_serialized_entry(key, ** ) rescue_error_with(nil) do @data.with { |c| c.get(key, ) } end end
#rescue_error_with(fallback) (private)
[ GitHub ]# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 327
def rescue_error_with(fallback) yield rescue Dalli::DalliError => error logger.error("DalliError (#{error}): #{error.}") if logger ActiveSupport.error_reporter&.report( error, severity: :warning, source: "mem_cache_store.active_support", ) fallback end
#serialize_entry(entry, raw: false, **options) (private)
[ GitHub ]# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 292
def serialize_entry(entry, raw: false, ** ) if raw entry.value.to_s else super(entry, raw: raw, ** ) end end
#stats
Get the statistics from the memcached servers.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 220
def stats @data.with { |c| c.stats } end
#write(name, value, options = nil)
Behaves the same as Store#write, but supports additional options specific to memcached.
Additional Options
-
raw: true
- Sends the value directly to the server as raw bytes. The value must be a string or number. You can use memcached direct operations likeincrement
anddecrement
only on raw values. -
unless_exist: true
- Prevents overwriting an existing cache entry.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 150
rdoc_method :method: write
#write_entry(key, entry, **options) (private)
Write an entry to the cache.
# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 251
def write_entry(key, entry, ** ) write_serialized_entry(key, serialize_entry(entry, ** ), ** ) end
#write_serialized_entry(key, payload, **options) (private)
[ GitHub ]# File 'activesupport/lib/active_support/cache/mem_cache_store.rb', line 255
def write_serialized_entry(key, payload, ** ) method = [:unless_exist] ? :add : :set expires_in = [:expires_in].to_i if [:race_condition_ttl] && expires_in > 0 && ! [:raw] # Set the memcache expire a few minutes in the future to support race condition ttls on read expires_in += 5.minutes end rescue_error_with false do # Don't pass compress option to Dalli since we are already dealing with compression. .delete(:compress) @data.with { |c| c.send(method, key, payload, expires_in, ** ) } end end


Library Metatheory
Require Export Coq.Arith.Arith.
Require Export Coq.FSets.FSets.
Require Export Coq.Lists.List.
Require Export AssocList.
Require Export CoqEqDec.
Require Export CoqListFacts.
Require Export LibTactics.
Require Export MetatheoryAtom.
We prefer that "==" refer to decidable equality at eq, as
defined by the EqDec_eq class from the CoqEqDec library.
Common set operations and constants may be written using more
convenient notations.
Notation "E [=] F" :=
(AtomSetImpl.Equal E F)
(at level 70, no associativity)
: set_scope.
Notation "E [<=] F" :=
(AtomSetImpl.Subset E F)
(at level 70, no associativity)
: set_scope.
Notation "{}" :=
(AtomSetImpl.empty)
: set_scope.
Notation "{{ x }}" :=
(AtomSetImpl.singleton x)
: set_scope.
Notation "x `in` E" :=
(AtomSetImpl.In x E)
(at level 70)
: set_hs_scope.
Notation "x `notin` E" :=
(~ AtomSetImpl.In x E)
(at level 70)
: set_hs_scope.
Notation "E `union` F" :=
(AtomSetImpl.union E F)
(at level 65, right associativity, format "E `union` '/' F")
: set_hs_scope.
We define some abbreviations for the empty set, singleton
sets, and the union of two sets.
Notation add := AtomSetImpl.add.
Notation empty := AtomSetImpl.empty.
Notation remove := AtomSetImpl.remove.
Notation singleton := AtomSetImpl.singleton.
Notation union := AtomSetImpl.union.
Open the notation scopes declared above.
Open Scope set_scope.
Open Scope set_hs_scope.
We can use our implementation of association lists (in AssocList)
to implement association lists whose keys are atoms. Thanks to
parameter inlining, the types in the instantiated functor will all
use atom for the type for keys.
We provide alternative names for the tactics on association lists
to reflect our use of association lists for environments.
Ltac simpl_env :=
simpl_alist.
Tactic Notation "simpl_env" "in" hyp(H) :=
simpl_alist in H.
Tactic Notation "simpl_env" "in" "*" :=
simpl_alist in *.
Tactic Notation "rewrite_env" constr(E) :=
rewrite_alist E.
Tactic Notation "rewrite_env" constr(E) "in" hyp(H) :=
rewrite_alist E in H.
Tactic Notation "env" "induction" ident(E) :=
alist induction E.
Tactic Notation "env" "induction" ident(E) "as" simple_intropattern(P) :=
alist induction E as P.
As an alternative to the x ~ a notation, we also provide more
list-like notation for writing association lists consisting of a
single binding.
Implementation note: The following notation overlaps with the standard recursive notation for lists, e.g., the one found in the Program library of Coq's standard library.
Implementation note: The following notation overlaps with the standard recursive notation for lists, e.g., the one found in the Program library of Coq's standard library.
Consider a rule H (equivalently, constructor, lemma, etc.) whose
type begins with forall L, ... and contains hypotheses of the
form (forall y, y `notin` L -> ...).
The tactic (pick fresh x excluding F and apply H) applies H to the current goal, instantiating H's first argument (L) with the finite set of atoms F. In each new subgoal of the form (forall y, y `notin` F -> ...), the atom y is introduced as x, and (y `notin` F) is introduced using a generated name.
If we view H as a rule that uses cofinite quantification, the tactic can be read as picking a sufficiently fresh atom to open a term with.
The tactic (pick fresh x excluding F and apply H) applies H to the current goal, instantiating H's first argument (L) with the finite set of atoms F. In each new subgoal of the form (forall y, y `notin` F -> ...), the atom y is introduced as x, and (y `notin` F) is introduced using a generated name.
If we view H as a rule that uses cofinite quantification, the tactic can be read as picking a sufficiently fresh atom to open a term with.
Tactic Notation
"pick" "fresh" ident(atom_name)
"excluding" constr(L)
"and" "apply" constr(H)
:=
first [apply (@H L) | eapply (@H L)];
match goal with
| |- forall _, _ `notin` _ -> _ =>
let Fr := fresh "Fr" in intros atom_name Fr
| |- forall _, _ `notin` _ -> _ =>
fail 1 "because" atom_name "is already defined"
| _ =>
idtac
end.
The following variant of the tactic excludes the set of atoms
returned by the gather_atoms tactic. Redefine gather_atoms if
you wish to modify the behavior of this tactic.
Tactic Notation
"pick" "fresh" ident(atom_name)
"and" "apply" constr(H)
:=
let L := gather_atoms in
let L := beautify_fset L in
pick fresh atom_name excluding L and apply H.
A number of useful lemmas are given standardized, if somewhat
unintuitive, names. Here, we define some intuitive aliases for
them.
Notation uniq_one := uniq_one_1.
Notation uniq_cons := uniq_cons_3.
Notation uniq_app := uniq_app_4.
Notation uniq_map := uniq_map_2.
Notation binds_one := binds_one_3.
Notation binds_cons := binds_cons_3.
Notation binds_app_l := binds_app_2.
Notation binds_app_r := binds_app_3.
Notation binds_map := binds_map_2.
Notation notin_empty := notin_empty_1.
Notation notin_add := notin_add_3.
Notation notin_singleton := notin_singleton_2.
Notation notin_union := notin_union_3.
The next block of hints is to help auto discharge many of the
inequality and freshness goals that arise in programming language
metatheory proofs.
Implementation note (BEA): The eassumption step is intended to address those cases where eauto tries to use a cofinite rule. The pattern goes something like this:
This ensures that the autorewrite step does not trigger an infinite loop.
Implementation note (BEA): The eassumption step is intended to address those cases where eauto tries to use a cofinite rule. The pattern goes something like this:
- Apply a cofinite rule with no idea what "L" should be. This adds a hypothesis x `notin` ?1 to the context.
- Apply the IH.
- eassumption resolves the x `notin` L obligation of the IH against the previously introduced x `notin` ?1 hypothesis.
This ensures that the autorewrite step does not trigger an infinite loop.
Ltac hint_extern_solve_notin :=
try eassumption;
autorewrite with rewr_dom in *;
destruct_notin;
repeat first [ apply notin_union_3
| apply notin_add_3
| apply notin_singleton_2
| apply notin_empty_1
];
try tauto.
Hint Extern 1 (_ <> _ :> _) => hint_extern_solve_notin.
Hint Extern 1 (_ `notin` _) => hint_extern_solve_notin.
The next block of hints are occasionally useful when reasoning
about finite sets. In some instances, they obviate the need to
use auto with set.
Hint Resolve
AtomSetImpl.add_1 AtomSetImpl.add_2 AtomSetImpl.remove_1
AtomSetImpl.remove_2 AtomSetImpl.singleton_2 AtomSetImpl.union_2
AtomSetImpl.union_3 AtomSetImpl.inter_3 AtomSetImpl.diff_3.
Implementation note (BEA): The following definitions make this
library usable with the output of Ott's locally nameless backend.
They may disappear or change as Ott changes.
Notation var := atom (only parsing).
Notation vars := atoms (only parsing).
Notation eq_var := eq_dec (only parsing).
Notation "x === y" :=
(x == y)
(at level 70, only parsing)
: coqeqdec_scope.
Notation "x \in s" :=
(x `in` s)
(at level 70, only parsing)
: set_sl_scope.
Notation "x \notin s" :=
(x `notin` s)
(at level 70, only parsing)
: set_sl_scope.
Notation "s \u t" :=
(s `union` t)
(at level 65, right associativity, only parsing)
: set_sl_scope.
Open Scope set_sl_scope.
Ltac gather_vars_with F := gather_atoms_with.
Ltac pick_fresh_gen L Y := pick fresh Y for L.
Tactic Notation "auto" "*" := auto.
Ltac apply_fresh_base H gather_vars atom_name :=
let L := gather_vars in
let L := beautify_fset L in
pick fresh x excluding L and apply H.
This page has been generated by coqdoc


isambard.ampal.assembly module¶
Defines various containers for AMPAL objects.
-
class
AmpalContainer
(ampal_objects=None, id=None)[source]¶ Bases:
object
Custom list type class that holds multiple model states.
Notes
In this case, a state is defined as a set of coordinates that represents a protein model and an associated score or set of scores.
Parameters: - ampal_objects ([AMPAL], optional) – A list of AMPAL objects with which to initialise the AMPAL container. This can be an Assembly, Polymer or Monomer.
- id (str, optional) – Identifier for the AMPAL container.
-
id
¶ str – Identifier for the AMPAL container.
-
pdb
¶ Compiles the PDB strings for each state into a single file.
-
class
Assembly
(molecules=None, assembly_id='')[source]¶ Bases:
ampal.base_ampal.BaseAmpal
A container that holds Polymer type objects.
Notes
Has a simple hierarchy: Assembly contains one or more Polymer, which in turn contains one or more Monomer.
Parameters: Raises: TypeError
– Assembly objects can only be initialised empty, using a Polymer or a list of Polymers.-
__add__
(other)[source]¶ Merges together two Assemblies.
Raises: TypeError
– Raised if other is any type other than Assembly.
-
append
(item)[source]¶ Adds a Polymer to the Assembly.
Raises: TypeError
– Raised if other is any type other than Polymer.
-
backbone
¶ Generates a new Assembly containing only the backbone atoms.
Notes
Metadata is not currently preserved from the parent object. Sequence data is retained, but only the main chain atoms are retained.
Returns: bb_assembly – Assembly containing only the backbone atoms of the original Assembly. Return type: ampal.Protein
-
buff_interaction_energy
¶ Calculates the interaction energy of the AMPAL object.
Parameters: - assign_ff (bool, optional) – If true the force field will be updated if required.
- ff (BuffForceField, optional) – The force field to be used for scoring.
- mol2 (bool, optional) – If true, mol2 style labels will also be used.
- force_ff_assign (bool, optional) – If true, the force field will be completely reassigned, ignoring the cached parameters.
Returns: buff_score – A BUFFScore object with information about each of the interactions and the Atoms involved.
Return type: buff.BUFFScore
Raises: AttributeError
– Raise if a component molecule does not have an update_ff method.
-
buff_internal_energy
¶ Calculates the internal energy of the AMPAL object.
Notes
THIS METHOD REDEFINES THE BaseAmpal VERSION. This is so that the force field is updated if any of its molecules need updating. This method is assigned to the buff_internal_energy property, using the default arguments.
Parameters: - assign_ff (bool, optional) – If true the force field will be updated if required.
- ff (buff.BuffForceField, optional) – The force field to be used for scoring.
- mol2 (bool, optional) – If true, mol2 style labels will also be used.
- force_ff_assign (bool, optional) – If true, the force field will be completely reassigned, ignoring the cached parameters.
Returns: buff_score – A BUFFScore object with information about each of the interactions and the atoms involved.
Return type: buff.BUFFScore
Raises: AttributeError
– Raise if a component molecule does not have an update_ff method.
-
extend
(assembly)[source]¶ Extends the Assembly with the contents of another Assembly.
Raises: TypeError
– Raised if other is any type other than Assembly.
-
fasta
¶ Generates a FASTA string for the Assembly.
Notes
Explanation of FASTA format: https://en.wikipedia.org/wiki/FASTA_format Recommendation that all lines of text be shorter than 80 characters is adhered to. Format of PDBID|CHAIN|SEQUENCE is consistent with files downloaded from the PDB. Uppercase PDBID used for consistency with files downloaded from the PDB. Useful for feeding into cdhit and then running sequence clustering.
Returns: fasta_str – String of the fasta file for the Assembly. Return type: str
-
get_atoms
(ligands=True, pseudo_group=False, inc_alt_states=False)[source]¶ Flat list of all the Atoms in the Assembly.
Parameters: Returns: atoms – All the Atoms as a iterator.
Return type:
-
get_interaction_energy
(assign_ff=True, ff=None, mol2=False, force_ff_assign=False)[source]¶ Calculates the interaction energy of the AMPAL object.
Parameters: - assign_ff (bool, optional) – If true the force field will be updated if required.
- ff (BuffForceField, optional) – The force field to be used for scoring.
- mol2 (bool, optional) – If true, mol2 style labels will also be used.
- force_ff_assign (bool, optional) – If true, the force field will be completely reassigned, ignoring the cached parameters.
Returns: buff_score – A BUFFScore object with information about each of the interactions and the Atoms involved.
Return type: buff.BUFFScore
Raises: AttributeError
– Raise if a component molecule does not have an update_ff method.
-
get_internal_energy
(assign_ff=True, ff=None, mol2=False, force_ff_assign=False)[source]¶ Calculates the internal energy of the AMPAL object.
Notes
THIS METHOD REDEFINES THE BaseAmpal VERSION. This is so that the force field is updated if any of its molecules need updating. This method is assigned to the buff_internal_energy property, using the default arguments.
Parameters: - assign_ff (bool, optional) – If true the force field will be updated if required.
- ff (buff.BuffForceField, optional) – The force field to be used for scoring.
- mol2 (bool, optional) – If true, mol2 style labels will also be used.
- force_ff_assign (bool, optional) – If true, the force field will be completely reassigned, ignoring the cached parameters.
Returns: buff_score – A BUFFScore object with information about each of the interactions and the atoms involved.
Return type: buff.BUFFScore
Raises: AttributeError
– Raise if a component molecule does not have an update_ff method.
-
get_ligands
(solvent=True)[source]¶ Retrieves all ligands from the Assembly.
Parameters: solvent (bool, optional) – If True, solvent molecules will be included.
-
get_monomers
(ligands=True, pseudo_group=False)[source]¶ Retrieves all the Monomers from the Assembly object.
Parameters:
-
helices
¶ Generates new Assembly containing just α-helices.
Notes
Metadata is not currently preserved from the parent object.
Returns: hel_assembly – Assembly containing only the α-helices of the original Assembly. Return type: ampal.Protein
-
is_within
(cutoff_dist, point, ligands=True)[source]¶ Returns all atoms in AMPAL object within cut-off distance from the point.
-
isoelectric_point
¶ Returns the isoelectric point of the Assembly.
-
make_pdb
(ligands=True, alt_states=False, pseudo_group=False, header=True, footer=True)[source]¶ Generates a PDB string for the Assembly.
Parameters: - ligands (bool, optional) – If True, will include ligands in the output.
- alt_states (bool, optional) – If True, will include alternate conformations in the output.
- pseudo_group (bool, optional) – If True, will include pseudo atoms in the output.
- header (bool, optional) – If True will write a header for output.
- footer (bool, optional) – If True will write a footer for output.
Returns: pdb_str – String of the pdb for the Assembly. Generated by collating Polymer().pdb calls for the component Polymers.
Return type:
-
molar_extinction_280
¶ Returns the extinction co-efficient of the Assembly at 280 nm.
-
molecular_weight
¶ Returns the molecular weight of the Assembly in Daltons.
-
pack_new_sequences
(sequences)[source]¶ Packs a new sequence onto each Polymer in the Assembly using Scwrl4.
Notes
The Scwrl packing score is saved in Assembly.tags[‘scwrl_score’] for reference.
Scwrl must be available to call. Check by running isambard.external_programs.scwrl.test_scwrl. If Scwrl is not available, please follow instruction here to add it: https://github.com/woolfson-group/isambard#external-programs
For more information on Scwrl see [1].
References
[1] Krivov GG, Shapovalov MV, and Dunbrack Jr RL (2009) “Improved prediction of protein side-chain conformations with SCWRL4.”, Proteins. Parameters: sequences ([str]) – A list of strings containing the amino acid sequence of each corresponding Polymer. These must be the same length as the Polymer. Raises: ValueError
– Raised if the sequence length does not match the number of monomers in the Polymer.
-
pdb
¶ Runs make_pdb in default mode.
-
primitives
¶ Generates a new Assembly containing the primitives of each Polymer.
Notes
Metadata is not currently preserved from the parent object.
Returns: prim_assembly – Assembly containing only the primitives of the Polymers in the original Assembly. Return type: ampal.Protein
-
relabel_atoms
(start=1)[source]¶ Relabels all Atoms in numerical order, offset by the start parameter.
Parameters: start (int, optional) – Defines an offset for the labelling.
-
relabel_polymers
(labels=None)[source]¶ Relabels the component Polymers either in alphabetical order or using a list of labels.
Parameters: labels (list, optional) – A list of new labels. Raises: ValueError
– Raised if the number of labels does not match the number of component Polymer objects.
-
sequences
¶ Returns the sequence of each Polymer in the Assembly as a list.
Returns: sequences – List of sequences. Return type: [str]
-
strands
¶ Generates a new Assembly containing only the β-strands.
Notes
Metadata is not currently preserved from the parent object.
Returns: strand_assembly – Assembly containing only the β-strands of the original Assembly. Return type: ampal.Protein
-
tag_atoms_unique_ids
(force=False)[source]¶ Tags each Atom in the Assembly with its unique_id.
Notes
The unique_id for each atom is a tuple (a double). unique_id[0] is the unique_id for its parent Monomer (see Monomer.unique_id for more information). unique_id[1] is the atom_type in the Assembly as a string, e.g. ‘CA’, ‘CD2’.
Parameters: force (bool, optional) – If True the tag will be run even if Atoms are already tagged. If False, only runs if at least one Atom is not tagged.
-
tag_ca_geometry
(force=False, reference_axis=None, reference_axis_name='ref_axis')[source]¶ Tags each Monomer in the Assembly with its helical geometry.
Parameters: - force (bool, optional) – If True the tag will be run even if Monomers are already tagged.
- reference_axis (list(numpy.array or tuple or list), optional) – Coordinates to feed to geometry functions that depend on having a reference axis.
- reference_axis_name (str, optional) – Used to name the keys in tags at Chain and Residue level.
-
tag_dssp_solvent_accessibility
(force=False)[source]¶ Tags each Monomer in the Assembly with its solvent accessibility.
Notes
- For more about DSSP’s solvent accessibilty metric, see:
- http://swift.cmbi.ru.nl/gv/dssp/HTML/descrip.html#ACC
DSSP must be available to call. Check by running isambard.external_programs.dssp.test_dssp. If DSSP is not available, please follow instruction here to add it: https://github.com/woolfson-group/isambard#external-programs
For more information on DSSP see [1].
References
[1] Kabsch W, Sander C (1983) “Dictionary of protein secondary structure: pattern recognition of hydrogen-bonded and geometrical features”, Biopolymers, 22, 2577-637. Parameters: force (bool, optional) – If True the tag will be run even if Monomers are already tagged
-
tag_residue_solvent_accessibility
(tag_type=False, tag_total=False, force=False, include_hetatms=False)[source]¶ Tags each Monomer with its Relative Residue Solvent Accessibility.
Notes
Relative Relative Solvent Accessibility is identified by NACCESS.
Parameters: - force (bool, optional) – If True, the tag will be run even if Monomers are already tagged.
- tag_type (str, optional) – Specifies the name of the tag. Defaults to residue_solvent_accessibility. Useful for specifying more than one tag, e.g. if the Polymer is part of an Assembly
- tag_total (bool, optional) – If True then the total RSA of the Assembly will be tagged in the total accessibility tag.
- include_hetatms (bool, optional) – If True, naccess will run with the -h flag. This means it will correctly run on structures with MSE, although the accessibility will be set to -99.9 for these residues. Probably best to check if your structure has these before using it.
-
tag_secondary_structure
(force=False)[source]¶ Tags each Monomer in the Assembly with it’s secondary structure.
Notes
DSSP must be available to call. Check by running isambard.external_programs.dssp.test_dssp. If DSSP is not available, please follow instruction here to add it: https://github.com/woolfson-group/isambard#external-programs
For more information on DSSP see [1].
References
[1] Kabsch W, Sander C (1983) “Dictionary of protein secondary structure: pattern recognition of hydrogen-bonded and geometrical features”, Biopolymers, 22, 2577-637. Parameters: force (bool, optional) – If True the tag will be run even if Monomers are already tagged
-


?The
New
York
copyright
reserved
botanical
Garden
AMERICAN
GRASSES
FROM
THE
U.
S.
NATIONAL
HERBARIUM,
SMITHSONIAN
INSTITUTION
1040.
Bambusa
vu
┴aris
Schrad
botanical
Cuba:
El
Cristo,
Province
Oriente.
Roadside.
Collector,
E.
L.
EKMAN
November
14,
1922
THIS
SPECIMEN
SHOULD
BE
CITED,
ĎAMER.
GR.
NAT.
HERB.
01529931
Legend -
Level of confidence that token is an accurately-transcribed word
extremely low
very low
low
undetermined
medium
high
very high


Waiting awkwardly for my talk to start. As A Service. #railsconf 4/22/2014, 11:33:50 AM Favs: 0 Retweets: 0 link


About Slimcoin
Slimcoin is a novel and experimental cryptocurrency created in 2014. It is the first known coin that uses the Proof of Burn mechanism to generate blocks. Additionally, it uses Proof of Work and Proof of Stake, making it the first and unique coin with three different block generation mechanisms.
In 2017, we’re alive and kicking, and we’re different from most other “altcoin” communities. We have no hierarchic and centralized structure - so we have no official development team that benefits from dubious pre-mine or insta-mine mechanisms.
All we want is to continue the exciting Proof of Burn experiment. In a few words, Proof of Burn is a mechanism where you get the right to find blocks if you burn coins.
Sounds crazy, huh? It is perhaps easier to understand as a process of virtual mining. We have prepared an simple explanation (ELI5). And it has very interesting economical properties. It is the only mechanism that allows the users to regulate the available supply in a decentralized way.
Learn more about Slimcoin’s advantages.
We’re an open project - you can participate
Our main discussion platforms are Bitcointalk and Reddit. Join us there!
We have also a wiki.
If you want to help with development & documentation: Go to our Github page.
Mining, Burning & Minting
Slimcoin can be generated in three ways:
- by Proof of Burn minting. That’s Slimcoin’s main innovation. Every coin you buy is a virtual mining rig. Here you find our Proof of Burn minting guide.
- by Proof of Work mining. It uses the DCrypt algorithm that is ASIC-unfriendly and can be well mined with CPU mining. We’ve prepared a Mining Guide for you.
- by Proof of Stake minting. This method is known from currencies like Peercoin. It’s perhaps the easiest method. Here you find a Proof of Stake Minting guide
Inscription service & Decentralized Websites
Since version 0.5, Slimcoin has a built-in blockchain website publishing service which lets you publish websites or blogs in a decentralized way without hosting nor domains. Simply publish your content as a torrent and let the Slimcoin blockchain be your version manager!
All you have to do is to use the inscription service provided by the Slimcoin client.
The publishing feature uses the awesome Web2Web and WebTorrent technologies. Your readers only need a modern browser - no additional software! So your voice will be heard also outside the nerd-space.
Stay tuned! This feature is still new and in alpha, and the Web2Web page generator has still to be ported. But you already can experiment with it.
Slimcoin Exchanges
You can trade, buy and sell Slimcoin at the following exchange:
Download Slimcoin & Source Code
You can download Windows, Linux and Mac OS binaries in our “Releases” section. The current beta release is 0.5. It is fully functional, but may still contain bugs.
The source code is here on Github. Chose the “master” or “0.5” branch if you want to test our new features.
About the Slimcoin project website
This website is still under construction. It is maintained by the Slimcoin community. If you want to contribute, please register at Github, fork the repository and create pull requests. Long-time community members can also ask for direct write access. Even if you don’t want to write content here - your suggestions are always welcome!


Home
4.7.2.RELEASE - 2nd February 2015
Enhancement
- [Enhancement] -
Skipping methods starting with "set" and having non single parameter
instead of throwing exception
Bug
- [Bug Fix] -
Properly handle immutable default values
4.7.1.RELEASE - 17th January 2015
Bug
- [Bug] -
Properly handle default values for collection and map types
3.0.5.RELEASE - 27th July 2013
Enhancement
- [Enhancement] -
Adding support for excluding fields based on custom annotations
3.0.4.RELEASE - 20th June 2013
Bug
- [Bug Fix] -
Resolve generics parameters in a safe and uniform way


The ‘mcpar’ attribute of an MCMC object gives the start iteration the end iteration and the thinning interval of the chain.
It resembles the ‘tsp’ attribute of time series (ts) objects.
ts
mcpar(x)
x
An mcmcm or mcmc.list object
mcmcm
mcmc.list
ts, mcmc, mcmc.list,
mcmc


Web Demo App
No User is Signed In
Tags
Name
Show Policy
ID
Show NPS
Show Survey
Show Rating Widget
Show Random Feedback Widget
Show Old Rating Widget
Show Old Rating Widget (Multi)
Fetch Remote Config (Header Color)
Send Custom Event
Change Device ID
Change device ID:
Please enter a valid device ID
Merge
OK
Cancel


16 years after war ended, Kosovo is looking to the future.
The Transformational Leadership Program – Scholarships and Partnerships (TLP), a partnership between World Learning and USAID, aims to support the next generation of leaders as they tackle Kosovo's economic, political, and social challenges. By providing technical assistance to the University of Prishtina and scholarships to study in the United States, the program builds the skills and resources young leaders will need to transform their country.
To learn more, press the right arrow key on your keyboard.
Internet Explorer is not supported at this time. Please load this presentation in a different browser.
The University of Prishtina (UP) is the largest public institution of higher education in Kosovo, enrolling nearly 54,000 students across sixteen faculties. The university boasts a rich heritage dating back to the 1960s. During the conflict-torn 90s, the government in Belgrade banned Kosovars from the campus, and university professors responded by creating a parallel system of classes in their homes.
Nonetheless, in the years since the war, spiraling student enrollment coupled with insufficient funding has hindered UP's forward movement.
The Transformational Leadership Program addresses the University of Prishtina's challenges head-on by providing technical assistance to the Office of the Rector. World Learning and its partners will improve the university's capacity to prepare graduates for the needs of Kosovo's growing economy and developing state.
They will support steps to enhance student life, teaching, research, external communications, and other core areas. Priorities include creating a Dean of Students Office, increasing academic exchanges with peer universities, and effectively communicating the progress of reforms to the public and broader University of Prishtina community.
The program also provides direct education and training opportunities. Over five years, TLP is awarding fully-funded scholarships for Kosovars to pursue 185 Master's degrees and 160 professional certificates at U.S. universities - even the cost of living is covered. These young leaders will study everything from aviation safety to game design to international relations in top programs across the United States.
When alumni return to Kosovo, they will be placed in key institutions, especially in the public sector, where they can employ their new knowledge and skills to influence change from within. Over time, this new generation will drive innovation, development, and reform in Kosovo.
Agnesa, a TLP scholar from the city of Pejë, personifies the next generation of Kosovar leaders. Growing up, she mastered English by listening to music and watching TV. She later became fascinated by the world of game design, the potential of games to create alternate realities and open players to new possibilities. As she says, "the experiences that [players] go through in games teach them [to be] open to any circumstance and any kind of individual - to expect anything from anybody."
In August 2015, Agnesa is bound for the U.S., where she will pursue a Master's in game design. When she returns to Kosovo, she plans to apply her new expertise to create a gaming community in Kosovo.
Kosovo, one of the world's newest countries, continues to invent itself. Key to this process are the passion, energy, and innovative thinking of the next generation of Kosovar leaders. The Transformational Leadership Program helps to ensure that, when these leaders take the stage, they will be equipped with the skills and training needed to transform their country.
Watch TLP scholars describe the program in their own words.
Follow us on social media to keep up with our work in Kosovo:


Travel, Photography, Video and I love bootstrap!
Section with three pieces of content
To go from one place to another, as by car, train, plane, or ship; take a trip; journey: to travel for pleasure..
Is the science, art and practice of creating durable images by recording light or other electromagnetic radiation, either electronically by means of an image sensor, or chemically by means of a light-sensitive material such as photographic film
A sequence of images processed electronically into an analog or digital format and displayed on a screen with sufficient rapidity as to create the illusion of motion and continuity.
Multiple headings to show use of the HTML header hierarchy


Mute new tabs
Mute all tabs on startup
Mute on origin change
Unmute when clicking a
volume control on a page
Automatic unmute is
supported on these domains
.
Report issue
|
Add rating/review


Koi's contemporary Japanese cuisine utilizes local and International ingredients. Among Koi's popular signature shared plates are Koi Crispy Rice topped with Spicy Tuna; Spicy Crunchy Yellowtail Tartare; Hamachi Fusion with Soy Yuzu and Truffle essence. Signature entrees include Miso-Bronzed Black Cod with Okinawa Potato Puree; Kobe Style Filet Mignon "Toban-Yaki"; and steamed Chilean Sea Bass with Ichimi, ginger, and shiitake. In addition to our signature rolls, Koi's sushi chefs present traditional topmost grades of seafood, including daily selections which are often celebrated by the modern and adventurous palate.