madbernard: a long angled pier (Default)
I've built a fair few open-source projects with small teams of four, and now I'd like to sling code as part of a company! I work with JavaScript presently, though I'd like to branch out into Java and Python (or should I do Ruby instead of Python? Some other language altogether? Feel free to advocate at me in the comments). I like both front-end and back-end work... It's nice that thanks to Node and MongoDB it's possible to be 100% JavaScript in your apps these days, though the API interfaces to other languages/databases generally feel very natural as well.

More project info & links, previous posts )

One of the neat things about the interviewing I've been doing is that I get to see a wide cross-section of the people who work in software development: there are people who have been working in the field since 1978 and have used every language that's come along in that time, and there are people who graduated their bootcamp last summer. Excited founders, people from other fields who learned rudimentary Python to desperately try to surf their wave of data, recruiters who seem to be honestly thrilled about their company....

I'm a meticulous, user-focused, communicative, easy-going, steely-eyed reliable developer, and I'd love it if you phoned or emailed or commented about Bay Area jobs that you'd like to see me at. Here's my resume with my contact info!
madbernard: a long angled pier (Default)
I use Safari for testing websites and for cruising Facebook, but it's been paining me that the tab-switching uses different keys than every other browser. Today, after absent-mindedly once again failing to move from the tab I was on, I searched for a way to customize the shortcuts. There's nothing specific to Safari, but... There is a Mac-wide way to set keyboard shortcuts, which can be made specific to Safari. And despite not restarting Safari after setting it up, I just absent-mindedly switched tabs and it worked! These are the instructions I followed. This is what I wrote in Step 4, just in case you need to make this change in your own life:
Show Previous Tab
Show Next Tab
(I was just so pleased that it worked. The dearth of Google results wasn't filling me with confidence.)
madbernard: a long angled pier (Default)
It takes a lot of time to figure out what's up with licensing code that you build, but a couple weeks ago I had the time to look it over, and I made this set of slides for a 5-minute talk on the subject.

The tl;dr is that all licenses descend from your ability to copyright stuff that you make. Copyright means that you can set the terms by which distribution happens there after, and so you can set Occupy-esque terms like "if you build from this, you have to show your source code and let other people freely build from your thing, too"...

Those terms above are the basic idea of free ("libre") software/"copyleft"/the GPL. Copyleft is a play on words from copyright, indicating that it means to be the opposite of the copyright, using its powers of control to ensure the thing will forever be freely available. The GPL has been tested in courts in the US and EU, and found to be solid.

My main concern with copyleft was, how much can you use it while keeping your thing separate? It seems like the answer is, if you're using, say, a MySQL database, no worries; but if you change the MySQL source code, that change must be liberated. I'm still not 100% sure of where the lines are, but then again, free software has proven itself as a working way of getting software distributed.

Open source licensed code, on the other hand, can be used by software businesses because an open source license doesn't require that you share source code. That, and the clarity and brevity of the writing, is why the MIT license has overtaken the GPL as most widely-used, I suspect.

There are more links in the slides to other discussions, and if anyone has opinions I'd love to hear them in the comments!
madbernard: a long angled pier (Default)
WebRTC (Web Real-Time Communication) is a plan to let there be plugin-less peer-to-peer sharing... In real time... Of anything. Back in the day, you had to download Flash or Silverlight or some other godawful program to use your webcam with the internet. Since HTML5, the ability for a browser to ask you for access to your webcam or microphone is built in to the spec.

There are three legs of WebRTC: the first, mentioned above, is the "getUserMedia" API, added to browser javascript, part of HTML5. The second and third are for WebRTC alone: the ability to maintain a direct computer to computer connection (forget the rest of the internet! We got us!), and the ability to exchange arbitrary data along that connection (for now, mostly live video). These second and third, which are specifically called RTCPeerConnection and RTCDataChannel, are something the browser makers should build in; but as of today, not all of them have.

Chrome, Firefox, and Microsoft Edge are up to speed on WebRTC: if you have one of them, go check out https://webcamtoy.com/ . It's a surprisingly fun website, and a source of great userpics. (I just tried visiting with Safari, to see what happened: the page let me know that I'd have to install Flash to continue. Good on them for having their ducks in a row, bad on Safari for not getting with the times.)

Of anything? ... Also, the ways the communication is done )

The tl:dr is, WebRTC: the browsers that care about security have set up a more secure real-time sharing service, and you don't need crummy programs any more to do interesting webcam things.
madbernard: a long angled pier (Default)
SQL: the godzilla of database languages! Knex/Bookshelf: a SQL query builder and a JavaScript ORM that works with it, built by Tim Griesser, supported through the issue tracker for each project at https://github.com/tgriesser/ . The Knex/Bookshelf pair make setting up and querying most of the SQL flavors of databases (Postgres, MySQL, MariaDB, SQLite3, and Oracle) more simple and readable, but I'm going to show the table creation mechanism below that I think is the best combination of the two:click to see lots of code! )
madbernard: a long angled pier (Default)
I was reworking some code caught in the wild to learn it, and it used both console.error() and console.info(). I'd heard that there were console methods beyond just our old friend console.log(), but I didn't know the details, so I turned to that beacon of righteousness: the Mozilla Developer Network. But wait: both had big red warning messages at the top of the page... And going up a level, console itself did also!
! Non-standard
This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.
Even console.log() has a warning! What? What does Stack Overflow say? I checked, and saw that most questions about console.log were from 2010/2011. I asked my housemate Ben the developer, and he said "check caniuse.com"...

Looks like in Internet Explorer 8 & 9, unless the console was open, it was undefined and console.log() would throw an error. Furthermore, caniuse.com has links to the GitHub where, in October 2013, a group got together and laid out how console should be used. I'm betting the MDN just has warnings because this Developer Tools Working Group isn't official, and the reason console.anything exists is entirely because the various browser coders decided to each do it with no prompting from, say, the W3C or ECMA.

The upshot is, console.log(), console.info(), console.warn(), and console.error() are all pretty much good to go if you don't need to support IE 9 or below. Also, this is why some ancient "learn Javascript" tutorials had all the reporting done with window.alert()... They come from the before times
madbernard: a long angled pier (Default)
Two great tastes... ...Not so much.

One part of the Hack Reactor program that my developer friends say is really accurate, in terms of preparing you for the real world, is the "Legacy" project. For four days, you and a team of three to four other people get to build anything you like, using any techs you like. Then comes the "Legacy": for four days, your team picks up another team's project and builds cool stuff out from their starting point. How do they techs they chose work for different people going in a different direction?

In my case, not 100% perfectly. So there was this day that I wasn't sure about how to dynamically generate a dropdown menu with Angular... I tried various methods and they weren't working... Eventually I tried just a straight-up, bog-standard <select></select> tag... Even that didn't show up...!

As you can probably guess from the title, the answer is, MaterializeCSS was not the right fancy CSS framework to use with a constantly shifting thing like Angular. Here's the Stack Overflow answer where someone gives a proper sermon about how MaterializeCSS falls short.

CSS/front-end frameworks make it easier to build a website that shrinks and bends well on a mobile phone, and that looks fine without a lot of poking. In fact, often these days you can look at a website and tell what it was made with, because developers are pretty happy to leave it as it came out of the box. MaterializeCSS is an attempt to look like Google's "Material Design" styles... Same paper-airplane-looking arrow for Submit/Send, etc.

However, apparently, MaterialzeCSS does some of its magic by overwriting normal HTML tags with its own... And any of its own things that require JavaScript to open or drop down or pop up must be initialized when the page loads... And anything that changes after the page loads LIKE SAY when a call to a database returns and populates a dropdown menu with options... Just doesn't happen.

Good times, good times.

You can see the website we worked on here: http://teslalegacy.herokuapp.com/ (If it takes many seconds to load, that's just because we're hosting it for free, and Heroku takes awhile to find it if no one has been there for half an hour). To see the glorious hand-crafted pop-up-div-full-of-checkboxes that I used instead of a drop down menu, you have to log in with GitHub. (Setting up a GitHub account will be worthwhile for you, anyway, but that's a story for another day.)
madbernard: a long angled pier (Default)
We got January 1st off, and after some computer erroring I was in the Stack Overflow network of sites, having actually asked a question about where Chrome stored its user data. Which inspired me to go find something to try to get enough points to be able to upvote all the people who had been so helpful to me over the last year.

I found a guy who had a question that almost boiled down to "Angular, how does it work". The literal day before I'd watched a lecture on that subject--I still had the tab open--so I took a crack at it, over the next few hours. You can see the results here.

I then started trying to implement his beautiful boxes website, using my own advice, to see if it was any good, so I could go back and actually truly help him. Making projects and studying in Hack Reactor kept me away from it, though. This is a note to self that I'd like to come back someday.

I did, at least, collect two people who thought the explanation was good enough for a vote... So now I can really be a part of the S.O. community. At last!

EDIT: Dave and I were chatting about this, and he was curious what the deal was with points on Stack Overflow. I wanted the points so that I could give props to all the people who have made my life better by writing great answers. You need 15 points to upvote, and each upvote you get gives you 10 points. At the very peak, aside from feeling somewhat good about themselves, the good answerers get to become mods if they choose.
madbernard: a long angled pier (Default)
I made a presentation on Basics of Web Accessibility to give to the 70-some people currently studying at Hack Reactor Remote with me! You can look at the slides here: http://slides.com/madelinebernard/webaccessibility/#/

The presentation went well, and I hope I left people with some good thoughts about the wealth of different people out there who could use our things on the web, and how to build for those people.

The next day, coding away on a bit.ly clone, my pair and I came to the point where we had to build a login form, and I realized that since I had literally just given the talk, I would have to walk the walk... I say on the slides, "Labels: if you do them right, clicking the word will tick the box (or whatever)". There are two ways to do this right, and over last week and next I've used both of them. Here they are:
<label for="login">Type your handle here!</login>
<input id="login" type="text"></input>

<label>Type your handle here!<input type="text"></input></label>
In the first, you have an "id" attribute on the labelled element, and the label's "for" attribute points to it. In the second, the <label> and </label> tags wrap the input element. I like the first better, since I can then lay out my code however I like; but the second is still there, for cases where everything's all in one place and it won't be messy to nest the tags but it would be messy to have a bunch of attributes.

The result, though, where you wave your hand, vaguely clicking in the area, and you get the cursor focused in the box... That's what the web oughtta be!
madbernard: a long angled pier (Default)
You probably know that when you have a URL like this, https://frontendmasters.com/hi/courses/crash-course?utm_source=bsa&utm_medium=ppc&utm_term=2015-12&utm_content=why-not-xmas&utm_campaign=crash-course, the weird mangled bit is not necessary for loading the page. I just learned why that is: the ? in the URL signifies that that's where the URL is starting to pass along info to receiving programs, and the info references something set up on the receiving end. And there's more to learn from the structure:
https://frontendmasters.com/hi/courses/crash-course?
utm_source=bsa&
utm_medium=ppc&
utm_term=2015-12&
utm_content=why-not-xmas&
utm_campaign=crash-course
those '&' are joining different references. The stuff before the equals sign references already-built containers to catch the possibly-varying info that is to the right of the equals sign. This is what I saw when rolling my own:

The guy I was paired with and I were having a time of it, figuring out how to tell a Parse server (https://parse.com/docs/rest/guide#queries-query-constraints) how to sort and shape the data we wanted it to return to us. It turns out that we could do it by sending our request to a URL different than the usual URL, which was https://api.parse.com/1/classes/. We instead sent a GET request (the normal "bring me a website, please") request to https://api.parse.com/1/classes/?order=-createdAt&limit=1000. Parse's documentation points out that it will accept parameters like "order" and "limit" and those take values like "field to sort by" and "number up to 1000", so with this URL we're telling Parse that we wanted the 1000 most recently created things... And it worked.

That was pretty great! It turns out that we were supposed to be using jQuery to make things tidier, though, so in the end we went with http://api.jquery.com/jquery.ajax/, filling the data: part of that with "data: {'order':'-createdAt', 'limit':'1000'},".
madbernard: a long angled pier (Default)
Woop! I've been silent because, some months back, I got into Hack Reactor Remote. It started Monday, and now I have a better sense of what they mean by their "please don't leak our secrets" note in their initial communications... They even suggested some things that make for possibly good blog posts.

Sidenote: I take paper notes because they served me well in college, and I've got vague impressions of research that indicates that things you hand write are things you remember better. (I should buy myself a notebook instead of doing archaeologically interesting things ie reusing paper that only has one side printed on.)

Next to me is a note of something Robin Kim, our technical mentor, said offhandedly (not his exact words):
When you have a bunch of console.log() reporters in your code to help debug it, include in them some indication of where they're coming from. So, like,
console.log('line 233', thing)
The comma is the separator to use in this instance.
He didn't say what made comma the best.

So this is neat because 1. obviously smart and useful idea and 2. wooo, even advanced coders still use console.log to debug! Putting break points in to the Chrome Dev Tools console has been great, also, but nice to know that Chrome Dev Tools are not necessarily the Only True Path.
madbernard: a long angled pier (Default)
Just did a Coderbyte challenge that was, "given an array of numbers that could be positive or negative but which will not include 0, return 'Arithmetic' for arrays where there's the same distance between all the numbers, 'Geometric' for arrays where there's the same multiple between all the numbers, and -1 for everything else." My answer isn't the best it could possibly be (I feel that I'm using Math.abs poorly, and I should have taken a moment more to make the reduce part bring back the biggest number in the difference array... averages can be deceiving), but looking at answers from unnamed other people, several of them don't even work. This one only compares the gap in numbers of the first two and last two in the array:
function ArithGeo(arr) { 
  var isArithmetic=(arr[1]-arr[0]==arr[arr.length-1]-arr[arr.length-2]);
  var isGeometric=(arr[1]/arr[0]==arr[arr.length-1]/arr[arr.length-2]);
  // code goes here  
  if(!isArithmetic&&!isGeometric){//is not special
    return -1;
  }else{
    return (isArithmetic)?'Arithmetic':'Geometric';
  }
}
It can be defeated with [1,2,45,99,100]. I saw this same pattern three times in like six answers I looked over. Interesting to catch stuff that the tests don't. When I started this post I was feeling a cheerful about not being at the bottom of the heap, but now I'm a bit sad. Anyway, here's my answer. Tell me about better ways of checking that every number in an array is the same... I could have done another for loop, "if difference array [i] !== difference array [0] return false"...
function ArithGeo(arr) { 
  var geo = [];
  var arith = [];
  for (var i = 0; i < arr.length - 1; i++) {
    geo.push(Math.abs(arr[i + 1] / arr[i]));
    arith.push(Math.abs(arr[i + 1] - arr[i]));
  }
  var sumGeo = geo.reduce(function(prev, curr){
    return prev + curr;
  });
  var sumArith = arith.reduce(function(prev, curr){
    return prev + curr;
  });
  if (sumGeo / geo.length === geo[0]) {return 'Geometric';}
  if (sumArith / arith.length === arith[0]) {return 'Arithmetic';}
  return -1; 
}
madbernard: a long angled pier (Default)
Here's one I thought would be simple, which wasn't. The problem is, "return a count of all the vowels (not y) in a string." I thought I'd use regex.exec to capture an array of vowels and find the length of the array... But it only ever returned length 2. I see in the Mozilla Developer Network info page that RexExp.length is 2, but I don't know why I'm getting that here. Can someone troubleshoot?
function VowelCount(str) { 
  var re = /([aeiou])/ig;
  var arr = re.exec(str);
  console.log(arr);
  return arr.length; 
}

console.log(VowelCount('moooo'));
So I pivoted to for loops and came up with this,
function VowelCount(str) { 
  var re = /[aeiou]/i;
  var count = 0;
  for (var i = 0; i < str.length; i++) {
    if (re.test(str.charAt(i))) {
      count += 1;
      console.log(i);
  }
  return count; 
}
This also took some troubleshooting, since the count was wrong when I was using the 'g' flag in the regex. I'm also not sure why that was. Other people I looked at also had mangled looking answers, though of course Matt Larsh has something good,
function VowelCount(str) { 
  var vowels = str.match(/[aeiou]/g);
  return vowels.length;
}
Looks like I need to bone up on str.match.
madbernard: a long angled pier (Default)
Last evening I had a moment and tried the Coderbyte challenge "when given a string of single letters, plusses, and equals signs, return true only if every letter has a plus on both sides". I came up with a four part if statement reliant on regexes.
function SimpleSymbols(str) {
  if (/(\+\w\+)+/g.test(str) && !/^\w/g.test(str) && !/=\w/g.test(str) && !/\w(?!\+)/g.test(str)) 
  {return true;}
  else {return false;}
}
In English, that's if there is a plus on either side of a letter, and if there is no letter at the start of the string, and if there is no letter with an equals sign immediately in front of it, and if there is no letter that is not followed by a plus sign... Then true.

Ben, who does JS for a living, gave me the learning that if there's more than one regex, it's probably not ideal... "There's so many edge cases". Makes sense. So, later, the Coderbyte challenge appears, "when given a string of lowercase letters, if there is an a followed by a b three spots later, return true". And I'm like, "I'll use a for loop, like we were talking about last night!"Read more... )
madbernard: a long angled pier (Default)
Challenge 5 was, given a number between 1 and 1000, add up all the numbers inclusive in that set. Obviously I could repurpose Matt Larsh's recursive function to do this, so I did so, and it worked first try. Woo! Though, no one else seems to be doing +=. I wonder if this would be super wrong if I wasn't recursing and thus seeing it only once each function call? Or do they just like num + SimpleAdding(stuff)?
function SimpleAdding(num) {
  if (num === 1) {
    return 1;  
  }
  else {
    return num += SimpleAdding(num - 1);
  }      
}
Challenge 6 was one I hadn't yet solved in Free Code Camp: Capitalize every word in a string. I abandoned a couple different paths while trying for speed, and eventually came up with this answer that seems cludgy:
function LetterCapitalize(str) { 
  var foo = str.split('');
  var bar = [];
  bar.push(foo[0].toUpperCase());
  for(var i = 1; i < foo.length; i++) {
    if (foo[i - 1] === ' ') {
      bar.push(foo[i].toUpperCase());
    }
    else {
      bar.push(foo[i]);
    }    
  }
  console.log(bar.join(''));
  return bar.join('');
}
LetterCapitalize('to see how to enter arguments in JavaScript');
I tried replacing the space in the if statement with /\s/ and that didn't work, nor did /\s/g; I'm not sure why not.

One of my abandoned paths was to do a str.replace(regex, function) but I wasn't getting the function to work... So I was super curious to see what Matt Larsh did, and sure enough he did something cool:
function LetterCapitalize(str) { 
  return str.replace(/\b[a-z]/g,function(c){return c.toUpperCase()});
}
That "\b" was something I thought should exist, but didn't find: the signal for "match a word boundary". I just tried /\b\w/g and that works, too; I suppose his way is better, though, since it limits the capitalization to only things that we absolutely know need capitalizing. Unless if \w includes accented letters and other slightly less usual things? My RegEx skillz are not yet l33t and m4d.
madbernard: a long angled pier (Default)
Remembering these from last week: Challenge 3 was another I'd done before, "find the longest word in the sentence", and I got a few more refinements in my answer: I used a regular expression to create the first array; and (having discussed it with Ben) I used an empty string as the initializing value. The previous stab at this Reduce, where I was trying to initialize with 0, was comparing apples and oranges in the form of numbers and strings.
function LongestWord(sen) { 
  var arr = sen.split(/(\w+)/g);
  var foo = arr.reduce(function(prev, curr){
    if(prev.length < curr.length){
      return curr;
    } else {return prev;}
  }, '');
  return foo; 
}
Looking over other answers, I think reduce is by far the most elegant path. Wooo! Arrays FTW!

Challenge 4 was ...a journey. Read more... )
madbernard: a long angled pier (Default)
I was just reading my friend Anneke's blog from before she did Hack Reactor. In this post she says
"I’m wrapping my head around Javascript’s call() and apply() methods. These get used a lot, and it’s important to understand just how they work. More immediately, these get used in the Hack Reactor pre-course work that I’m working my way through ..."
That crystallized an opinion in me: I want my learning materials to have opinions, because opinions are context.

Eloquent Javascript presents as a textbook, ie "neutral", but since Marijn Haverbeke is a guy with strong opinions they sometimes leak through and make the book way more valuable to me. Codecademy, on the other hand, just presents one thing after another. Last year I asked Ben-the-housemate to help troubleshooting a switch statement project there, and he had to look up the syntax, despite coding JavaScript every day. He explained that switch statements are almost never used. That kind of thing is gold! I'm happy to learn about switch statements, but knowing what the actual bread and butter of a language is is far more helpful. Anneke passed me the Functional Programming in JavaScript page, where Jafar Husain says,
"[map, filter, concatAll, reduce, & zip] will probably be the most powerful, flexible, and useful functions you'll ever learn."
That's what I'm talking about! I'd love to know enough to be able to debate about what is best in JavaScript. Wrangling in forums (well moderated forums that don't allow personal attacks), or watching such wrangles, is the best way to see all sides of a thing.
madbernard: a long angled pier (Default)
Factorial happened last week, also; the CoderByte challenge was, we'll test on numbers between 1 and 18, give us that number multiplied by every non-0 integer less than it. Ben-the-housemate suggested that this could be done recursively, so I tried that first, but didn't hack it; so, given the ticking clock, I aborted to the exact same decreasing for-loop plan I'd used last week. Looking through other answers was gratifying... I was among the most elegant! I found the recursive method from user mattlarsh, in a tiny tidy package:
function FirstFactorial(num) { 
  return num<=1?1:num*(FirstFactorial(num-1)); 
}
He's using the ternary operator there, the shortest possible way to say if/then. IF: the num is less than or equal to 1, DO THIS: return 1, AND IF IT'S NOT: multiply the num by FirstFactorial num-1. So once he has a stack of not-quite-resolved functions and the num gets to 1, it returns 1 and then the rest of the stack has all the numbers it needs to work with and can resolve the final return.

My first pass on recursion was the below, and I got stack overflow (infinite program), which I can see now is because the num kept getting bigger but the recursion would only end when the num got to 0.
function FirstFactorial(num) { 
if (num > 0) {
num *= (num - 1);
FirstFactorial(num);
}
  return num; 
}

FirstFactorial(5);   
madbernard: a long angled pier (Default)
I looked at the Hack Reactor suggestions for what one should be able to do before applying, and headed over to http://www.coderbyte.com to try their easy track. They score submissions based not only on correctness, but on time, which is not at all my bag. I think when I saw that a year ago I just turned away, even though a friend suggested doing it on my own time and then pasting the answer in... I might do that in the future.

Their first question was the exact same as I saw last week; reverse a string. I came up with this, which, amusingly, is not what I did last week. It uses the join method of arrays that I was searching for last week, so I'm pleased that knowledge is in me...
function FirstReverse(str) { 
  var hold = [];
  for(var i = str.length - 1; i >= 0 ; i--){
    hold.push(str[i]);
  }
  var foo = hold.join("");
  return foo; 
}

FirstReverse("stuff");           
Also, heeey, check out the respect of spacing in that code block. I thought there were HTML tags about code, and found <code> and thought that was it... Ben the housemate says code isn't really a HTML tag and turned me on to <pre>. Thanks!

Anyway, a good thing about CoderByte: they let you see what other people did, after, answering the socrating question of my friend Catherine about whether I looked at other people's solutions. There's a solution like mine above, but relying on methods of strings and arrays that I wasn't aware of; and that solution lets one do everything in a single line!
function FirstReverse(str) { 
  return str.split('').reverse().join('');
}
Way more elegant.
madbernard: a long angled pier (Default)
The next Free Code Camp exercise is to find the length of the longest word in a string (and all of their test strings are free of anything but letters and single spaces). Good points: I had no trouble getting the shape of the solution, and split totally worked great. Actually doing the proper syntax for Reduce required a lot of searching, though, and eventually I basically copied a bit from this webpage about getting comfy with arrays. I should work through that website sometime... Most of the failed reduce trials I don't have copies of, but one that I don't understand is that when I had a 0 in the place I thought was for initial value, right after the anonymous function and before the console.log error-catching readout, here: }, 0);
console.log(foo.length);
what I got out of the function was only 0. Baffling. Below is code that works. :)

function findLongestWord(str) {
var words = str.split(' ');
var foo = words.reduce(function(prevWord, thisWord){
if (thisWord.length > prevWord.length) {
return thisWord;
}
else {
return prevWord;
}
});
console.log(foo.length);
return foo.length;
}

findLongestWord('The quick brown fox jumped over the lazy dog');

May 2016

S M T W T F S
1234567
8910 11121314
15161718192021
22232425262728
293031    

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated May. 26th, 2017 01:09 pm
Powered by Dreamwidth Studios