dennisgorelik: (Default)
Muhammad contacted me on LinkedIn:
M: Hi Dennis,
As one of my connections, I wanted to quickly reach out to see if you have any current or future opportunity for me?
I am based in Islamabad Pakistan.
{Long list of buzzwords and self-praise skipped}
D: What's your hourly rate?
M: Hi Dennis, thanks for your response.
I am happy if I can get $40+ /hr. Incase of remote opportunity $20/hr is good.

We chatted on LinkedIn a little about his participation in nTaskManager project.
I pointed out to a misspelling in his resume "Windows Azuer" (which is not a good sign), but he fixed it (which is a good sign) and said "thank you" for that.

I was not able to get answers from Muhammad to my specific technical questions and was considering dropping it, but Muhammad offered to talk on Skype.
So I decided to try and see what would happen. In particular, my goal was to learn how text chat correlates with voice conversation over Skype.
Muhammad proved to be consistent: he could not answer my specific tech questions in text chat, and he could not answer my specific questions in our voice conversation.

Transcript of our voice interview
D: Hi Muhammad.
M: Hi Dennis, how are you.
D: Let’s start with question about email that this nTask sends (*1). Did you create this email?
M: Actually, I created this with the team. It was not only my task. I think it was team of 5 persons. I see your screen.
D: So, yes, I’m talking about this email. Did you participate in any way in creating this email.
M: Actually, my participation was only technical: creating technical design, ..., creating technical implementation , ...
D: So, did you do anything about this email. Anything. Any activity. Did you put any work into this email?
M: There are 2 things: one is content and second one is how email is being sent. What I implemented is to send emails. This email template was designed by our designer, and content was designed by the owner of this application. My role was to write code, so this email will be sent.
D: When this code was (*2) ... are you saying you wrote code that was sending this email? Or you are not saying this? Or you did not do it?
M: Sorry, I could not get what you said.
D: Did you write the ... I still cannot understand what you did here. Did you do anything here? Or you actually wrote code for sending this email. Or was it somebody else who was doing it?
M: I was writing the code.
D: You were writing the code. Ok. How many developers were writing code that sends this email?
M: I had one front-end developer...
D: Uh-huh.
M: ... and one SQL guy with me, and I was only backend developer. And the code was written in C#. And we were using Mongo DBs database.
D: So could you explain, in this email, what was the backend work and what was the front-end work, and which part did you do, specifically? In this email.
M: Actually, as a backed it is, actually MVC single-page application. And this is using ...
D: [Interrupting] Ok, now you mention MVC. Single page application. What does it have to do with MVC? Like this email – what does it have to do with MVC?
M: Actually, MVC is the main framework for this.
D: What do you mean? Are you saying you are using MVC in order to create email?
M: No-no-no. Definitely there is an application. It’s a complete architecture. Having multiple ... for database, operations, sending emails...
D: So, we are talking specifically about email. Do you understand it, right? We are talking specifically about sending email. I am asking you specifically about this email. You were mentioning MVC. Why were you mentioning MVC in the context in the email?
M: Sorry, I were talking about overall architecture ...
D: [Interrupting] No, we were not talking about overall architecture. I was talking, specifically, about this email. I am not talking about overall architecture. Did I say “overall architecture”?
M: N ... this specific email – there is nothing special, just Microsoft [unclear] just register. Request will go to the server. Once your account is created. And we are sending email to just verify you enter your own email address, to avoid spamming.
D: Uh-huh.
M: There is not special, there is just as way for emails.
D: Ok. And?
M: What do you mean “and”? ... I think there is nothing special or complicated in sending email.
D: Ok, Muhammed, here’s what I noticeD: you do not answer my questions. Ok? It looks like you do not even understand them.
M: Sorry, can you repeat the question?
D: I asked you several questions. During this conversation (while we are talking for, like, 3 minutes now) I asked you several questions. You answered almost none of them.
M: Yes, can please start with one by one. I will be answering.
D: All right. So, one of my question was: “Did I ask you to talk about overall architecture?”.
M: Eh, sorry, I was talking about what is the overall implementation of this project. And you asked me what was your role. I was talking about my role. My role was to create an architecture.
D: Ok, it looks like you, again, did not hear my question. Could you repeat my question before you answer that? (*3).
M: Sorry, actually, when we were talking about few seconds ago, and you just asked what was my role. And my role was from multiple tasks. So, I talked about the architecture and MVC-like things in the context of my role.
D: So, context of your role... Context of your role in what? What do you think I asked you?
M: Actually, I understand it was, there you wanted to ask me what was my role on this application, and I was just explaining my role on this application.
D: On “this” – on what “this” application? What do you mean under “this” application?
M: “This application” means “nTaskManager”.
D: I did not ask you that! I did not. I asked you, specifically, about this email.
Ok, Muhammad, I think there is no point to waste the time. I see what would happen going forward. You do not understand my questions – we are not able to work together. Thank you.
M: Thank you.
D: Bye.

Foot notes
(*1) - The email subject is "Complete your nTask Registration". Email messaging is very important for my business, so I decided to start conversation with it.
(*2) - I started asking Mohammad about "when this code was written", but then changed my mind mid-sentence and moved on to the question that focused on his role in creating this email.
(*3) - At this point I sound noticeably angry, and that makes Muhammad a little bit nervous.

What do you think: if interviewee is not able to repeat my question and instead talks about a different topic - is it reasonable to terminate interview at that point?
dennisgorelik: (Default)
Electricity came back yesterday after ~16 hours of downtime.
AT&T brought Fiber Internet back today after ~35 hours of downtime.

T-mobile had phone and mobile Internet connection without downtime. I wish all services were working without downtime like that.
After all it was only Category 1 hurricane when it reached us, which is not a good excuse to lose services.

dennisgorelik: (Default)
I asked my (PostJobFree) contractor why he did almost no work recently.
According to that contractor explanation, one of his key reasons not to work was that he did not get paid for over a year.
I reminded him that he did not send his invoice (with the summary of what was done), and, according to our agreement - I pay when he sends such invoice..
The contractor agreed that he did not send the invoice, but still insisted that the lack of payments was demotivating.

Would you struggle with sending your work summary in order to get paid?
dennisgorelik: (Default)
Polk County sheriff tweeted a controversial warning:

Map of Polk county

Street view of the Sherrif office and Jail
dennisgorelik: (Default)
We are using Amazon SES to send over 10M emails per month.
This is cheap and reliable service, and overall I like it.
However customer support is poor.

Recently, Amazon SES team removed 2 important graphs from their SES dashboard: "Bounce rate" and "Complaints".
Apparently, Amazon SES team decided that customers would be happier to build their own reports on buggy CloudWatch instead of using already prepared report.

I complained that "development" on AWS forum, and here is the reply:

The proposed solution - does NOT work.

To add an insult to the injury, AWS forum does not allow me to reply yet with a message: "Your message quota has been reached. Please try again later."

Here is my forum reply that I am NOT able to post on AWS forum yet:

1) Thank you for trying to help.
I followed your steps and this produced two graphs to me.
Both graphs have constant horizontal lines at 1.00 level.
So, pretty much, both graphs are totally useless.

Should I use instead different "metrics" instead of "Bounce" and "Complaint"?
"Reputation.BounceRate" and "Reputation.ComplaintRate" perhaps?

2) Do you know why Amazon SES Team decided to make us (its customers) to jump through the hoops of creating these awkward custom reports instead of just keeping already existing functionality?
This exercise is time-consuming, and while I am troubleshooting cloudwatch app - I am NOT building my own app that pays the bills for all of us.

3) "Your message quota has been reached. Please try again later. " ... this is my second message (and the first message in ~12 hours).
It looks like Amazon SES Team is not eager about receiving feedback...

Accidentally, few days ago I received email from SendGrid rep that suggested me it may be a time to switch away from Amazon SES to SendGrid in order to get a superior customer support.
I asked SendGrid rep what kind of support I may need, got no clear reply. But Amazon SES team seems to be happy to prove their competitors right.

See also:
dennisgorelik: (Default)
In "Double.NaN != Double.NaN" discussion, [personal profile] ppk_ptichkin linked to Ariane 5 investigation.

My conclusions based on that investigation:
1) Delete unused code from the solution.
2) Make sure that the application is still functional, even in case when an exception happens.
3) Do integration tests.

e) At 36.7 seconds after H0 (approx. 30 seconds after lift-off) the computer within the back-up inertial reference system, which was working on stand-by for guidance and attitude control, became inoperative. This was caused by an internal variable related to the horizontal velocity of the launcher exceeding a limit which existed in the software of this computer.

f) Approx. 0.05 seconds later the active inertial reference system, identical to the back-up system in hardware and software, failed for the same reason. Since the back-up inertial system was already inoperative, correct guidance and attitude information could no longer be obtained and loss of the mission was inevitable.

g) As a result of its failure, the active inertial reference system transmitted essentially diagnostic information to the launcher's main computer, where it was interpreted as flight data and used for flight control calculations.

h) On the basis of those calculations the main computer commanded the booster nozzles, and somewhat later the main engine nozzle also, to make a large correction for an attitude deviation that had not occurred.

i) A rapid change of attitude occurred which caused the launcher to disintegrate at 39 seconds after H0 due to aerodynamic forces.


m) The inertial reference system of Ariane 5 is essentially common to a system which is presently flying on Ariane 4. The part of the software which caused the interruption in the inertial system computers is used before launch to align the inertial reference system and, in Ariane 4, also to enable a rapid realignment of the system in case of a late hold in the countdown. This realignment function, which does not serve any purpose on Ariane 5, was nevertheless retained for commonality reasons and allowed, as in Ariane 4, to operate for approx. 40 seconds after lift-off.

n) During design of the software of the inertial reference system used for Ariane 4 and Ariane 5, a decision was taken that it was not necessary to protect the inertial system computer from being made inoperative by an excessive value of the variable related to the horizontal velocity, a protection which was provided for several other variables of the alignment software. When taking this design decision, it was not analysed or fully understood which values this particular variable might assume when the alignment software was allowed to operate after lift-off.

o) In Ariane 4 flights using the same type of inertial reference system there has been no such failure because the trajectory during the first 40 seconds of flight is such that the particular variable related to horizontal velocity cannot reach, with an adequate operational margin, a value beyond the limit present in the software.

p) Ariane 5 has a high initial acceleration and a trajectory which leads to a build-up of horizontal velocity which is five times more rapid than for Ariane 4. The higher horizontal velocity of Ariane 5 generated, within the 40-second timeframe, the excessive value which caused the inertial system computers to cease operation.



On the basis of its analyses and conclusions, the Board makes the following recommendations.

R1 Switch off the alignment function of the inertial reference system immediately after lift-off. More generally, no software function should run during flight unless it is needed.

R2 Prepare a test facility including as much real equipment as technically feasible, inject realistic input data, and perform complete, closed-loop, system testing. Complete simulations must take place before any mission. A high test coverage has to be obtained.

R3 Do not allow any sensor, such as the inertial reference system, to stop sending best effort data.
dennisgorelik: (Default)
Google Cloud Platform performs with pathetic 99.8% uptime - worse than the cheapest hosting providers.
Last month we got 326 crashes out of 172,922 API requests.

See also:
Google Maps API team wants to get paid more
Decline of Google Maps team
dennisgorelik: (Default)
Today Moon's shadow is going to cross from Pacific to Atlantic coast of the US in 90 minutes:

It takes passenger jet 3.5 hours to fly the same distance (e.g. from San Francisco to New York)

We (in Ponte Vedra, FL) are going to see only partial ~90% solar eclipse.
San Francisco is going to get 75% of the eclipse 90 minutes ahead of us.
dennisgorelik: (Default)
I think it's more likely that your "great programmers" simply understand the difference between the same functionality and accidentally similar functionality. The latter is where you have two use cases that are very similar, so you spend all this time deduplicating. Then one of the use cases changes... The correct response would be to duplicate the code again, because the two use cases are no longer similar. In reality, they should have never been combined in the first case. They weren't the same; they were only accidentally similar.
But instead what you usually see is minor tweaks to the common functions. Pass in a flag here, tweak the inputs there, add an if statement over yonder... And before you know it, it's all a terrible tangled mess that is full of branches and technical debt. The two use cases have the same functions, but don't even follow the same branches within the functions.
dennisgorelik: (Default)
Waterfall sightseeing in Yemen on Google Maps

1) Garbage.
2) Males clothes.
3) Females closes.

Yemen GDP per Capita: $990/year
dennisgorelik: (Default)
Жертва пропаганды бьет пропагандиста кремля. РФ 21 век.

Страница нападавшего:

Полный выпуск НТВ:

На мужчине, напавшем на Развозжаева, надета футболка с надписью «Оплот». Так называется созданная на Украине организация, которая выступала против «Евромайдана» и занимала пророссийскую позицию.

Александр Орлов, задержанный: «Слушайте, я готов принести извинения и денежную компенсацию. Давай добазаримся. Я не хотел. Просто я иду, и он мне какую-то гадость говорит, а я ему руку кинул, и все».
dennisgorelik: (Default)
I was surprised today that very few people understand what falsifiability means and how to apply that useful evaluation tool.

Of course I knew pretty well, that an average person has no idea about what Popper's criteria of falsifiability is.
But most of my online friends do not understand what "Falsifiability" means either.

It is a pity, because Falsifiability criteria - is a very powerful tool that allows to quickly separate potentially useful theories from pseudo-scientific scam.

Hopefully my friends understand better what testability is (the meaning of "testability" and "falsifiability" overlaps a lot).
dennisgorelik: (Default)
About half a year ago my dentist told me that there is a decay below my tooth bridge. Therefore that the bridge needs to be re-done (at the cost of around $4,000). She insisted, that tooth decay is not reversible.
When I asked her if a tooth can heal itself - she said that it is possible, but only if decay did not reach below enamel.
In the following months I started to pay more attention to flossing and rinsing around that problem space, and yesterday went to another dentist for a cleanup and dental exam.

New dentist found decay below the bridge and recommended to replace it (at the cost of $4,814). He insisted, that tooth decay is not reversible. When I asked him if a tooth can heal itself - he said that it is possible, but only if decay did not reach below enamel.

The good news for me is that the new dentist did not find any problems with the bridge that my previous dentist wanted to re-do.
And my previous dentist did not find any significant problems with the bridge that the new dentist wants to fix.

In addition to replacing bridge, the new dentist suggested to pull my 4 wisdom teeth ($236 each) and re-do a filling ($350).

The question is - how do I know know what recommendation has a merit and what recommendation is just a money grab?
dennisgorelik: (Default)
Пенсии не будет. Старости, впрочем, тоже. Как и работы. Будет одобренная Роскомнадзором и РПЦ виртуальная реальность, где вы будете вечно брать Сталинград.
dennisgorelik: (Default)
Short names vs unique names
It is a good practice to use shorter method names, because long names are harder to read.
It is cleaner to call:

But then we end up with multiple "Save()" methods in different classes. For example:

Problem with non-unique names
If we search our codebase for "Save(" - we would find a lot of methods and method calls. Only some of them would relate to the functionality we actually want to research (for example, we may want to research where "Candidate Save()" functionality is used because we consider refactoring or deleting it).

Plain text search vs code references
Visual Studio allows to find all references to a specific method by right-mouse-clicking on a method name and selecting "Find All References".
So, non-unique method names problem is solved, right?
Not quite.
Visual Studio is not able to track method calls that are made from aspx and ashx files.
Visual Studio is also not able to find method references in the comments.

ReSharper vs vanilla Visual Studio
ReSharper actually is able to find method references in aspx, ashx and even in comments. Until Visual Studio 2015 that worked fine. But since ReSharper team and codebase aged, and Visual Studio switched to new Roslyn compiler, ReSharper team was not able to keep up and delivered only barely working resource hog, that is practically not usable with newer version of Visual Studio (too slow).

Get rid of aspx and ashx files?
It is actually pretty easy to avoid using ashx handlers and use standard C# classes to implement HttpHandler interface.
But what about aspx pages: can we get rid of them too and use only standard C# HttpHandlers?
If we could do that, then we would be able to rely on "Find All References" feature again.
But, unfortunately, getting rid of aspx pages is not that simple. We would have to reimplement a lot of functionality that aspx has.
For example:
- Page PostBack support would be gone.
- Ability to nicely combine HTML code and aspx controls alongside each other would be gone.
- HTML syntax validation would be gone (no HTML syntax validation for C# strings in Visual Studio).

If it ain't broke - don't fix it
Even though it is pretty straightforward operation to convert existing ashx files into standard C# classes (where Visual Studio is able to track all method references) - such conversion is not without its own problems.
- Conversion takes developer's time.
- Code replacement could introduce silly bugs.
- Moving code from class to class makes navigating "svn blame" - a little bit trickier.
So if an ashx handler was working in the solution for many years already - does it make sense to touch it now?

The benefits of code refactoring
In spite of "If it ain't broke - don't fix it" rule - cleaning up code is still needed. If we do not keep code clean (do not delete unneeded parts and do not clear confusing things such as hidden references) - then our codebase would be extremely hard to maintain. Fixing a bug would introduce other bugs. Features would be very hard to add without adding bugs.

It depends
There is no single solution that can be applied to all situations. In software development we consider multiple problems and constantly weigh pros and cons against each other.
For example, out of 11 remaining ashx files, we:
- Deleted one file because we do not use it ("Reduce amount of code when possible" principle).
- Would migrate one file to the standard C# HttpHandler, because today during refactoring a developer missed a method call from that ashx file.
- Keep other 9 ashx files as is ("If it ain't broke - don't fix it" principle).

What are your examples of balancing problems against each other?
dennisgorelik: (Default)
One of our existing air-conditioners is about to die soon.
So we need a replacement. But which one?

Currently we need a smaller unit for the second floor.

Carrier system
One of AC installer companies recommend "Carrier" system:
Cooling Capacity : 22000
Heating Capacity : 21600
SEER : 14.5
EER : 12
HSPF : 8.2

Heat Pump Carrier 25HCE424A003
-10 year parts limited to original purchaser upon timely registration (otherwise 5 years).

Air Handler Carrier FV4CNF002L00
- Variable Speed

Auxiliary Heater Carrier CE0501N05

Thermostat Carrier TP-WEM01
- Wifi Capable.
- 5 year warranty if registered in a timely manner.
Price (including installation): $5,699

That choice seems a little bit pricey for a small AC unit. But what do you think?

Most homeowners report spending between $3,710 and $7,140 to have air conditioning installed. This price is more typical of a central A/C unit installation rather than a window central air conditioner addition which typically averages about $300.
dennisgorelik: (Default)
Couple of years ago security pen testers found clickjacking bug in Google API Explorer:
Google did pay out a $1,337 bounty
“The idea behind the exploit is to frame the page where that button was, and make the frame transparent.”

Here is the demo of how highjacking setup page looks like:
Hijacker's web site content that invites user to click somewhere:
<p><input type="button" value="Click to see cats' videos"></p>
iframe { 
position: absolute;
top: 0; left: 0; 
filter: alpha(opacity=50); 
opacity: 0.50;
<iframe src="">
Note that Wikipedia's security team made a conscious choice to allow clickjacking of their home page, because there is nothing at risk there.
But if you click "Log in" (or replace "" with "" in the demo html above) - you would notice that Wikipedia login page is not rendered in the iframe.

How did Wikipedia do that?
I opened Fiddler2 debuggin proxy and found out that "" renders this HTTP header:
X-Frame-Options: DENY
But "" page does NOT render that header.

How to prevent clickjacking?
Extra experimenting showed that, and use "X-Frame-Options: SAMEORIGIN" uses "X-Frame-Options: DENY" (the same as Wikipedia login page).
There are three possible directives for X-Frame-Options:
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
X-Frame-Options: ALLOW-FROM

What is the best practice for using "X-Frame-Options"?
I am trying to decide what "X-Frame-Options:" should I use for
Does the flexibility of iframe worth the security risk?
Should we support web site that include content into their own iframe?
Such iframe support has both cons and pros...

Why secure option is not a default choice in browsers?
What do you think, why browsers (such as Google Chrome and Firefox) do not assume "X-Frame-Options: SAMEORIGIN" by default?
If allowing loading your page content into parent iframe is inherently insecure, then such a risky behavior should be explicitly requested, right?
dennisgorelik: (Default)
How-to create a VM on Hyper-V
Yesterday I learned how to setup a new virtual machine from scratch on Hyper-V.
Then I created an instruction for that:

1) Install "Hyper-V" (if not installed yet)

2) Launch "Hyper-V Manager".

3) Create Virtual Network Switch (if not created yet)
- Right-click "RONAM" -> "Virtual Switch Manager".
- "New virtual network switch" -> "External" -> click [Create Virtual Switch].
- Make sure that "External network" is selected.
- Make sure that "Intel(R) Ethernet Connection (2) I219-LM" is selected.
- Click [Apply].
- "Pending changes may disrupt network connectivity" popup would show up. Click [Yes]. Wait for ~10 seconds.

4) Right-click "RONAM" and select "New" -> "Virtual Machine".

5) "Specify Name and Location"
Name: "BaseVM"
Location: "C:\VM"

6) "Specify Generation"
Select "Generation 2" radiobutton.

7) "Assign Memory"
Startup memory: 4096 MB 

8) "Configure Networking"
Connection: "VS2017Switch"

9) "Connect Virtual Hard Disk"
Select "Create a virtual hard disk" radiobutton.
Size: 80 GB.

10) "Installation Options" sub-tab
Select "Install An Operating System From A Boot CD/DVD-ROM".
Image file (.iso): "C:\install\en_windows_server_2016_x64_dvd_9718492.iso"

11) "Summary"
Click [Finish].

12) Right-click "BaseVM" -> "Start".
That would start Windows installation.

Then I asked K. (a developer on my team) to test my instruction by creating a new VM from scratch and fix the instruction if needed.

The "fix"
K. successfully created new VM and "fixed" the instruction by adding small details to it. That effectively made that instruction about 25% longer:
Read more... )
Formally, that "fixed" instruction is correct -- clicking "Next" button is one of the likely steps that person would take in order to go through new VM settings.
However including "Click [Next]" steps into the instruction makes instruction worse and not better, and here is why:
1) The longer the instruction - the harder it is to read, understand, and follow that instruction.
It is also harder to review and modify longer instructions.
2) The obvious steps in an instruction - distract the reader from the non-obvious steps, such as "what 'Generation' option to choose" and "how much RAM to allocate".
3) Any user who is going to create a new VM from scratch does not really need to get instruction on how to operate the wizard:

Understand your readers
Here is a rule that K. violated by "fixing" the instruction:
Do NOT include into instruction steps that are obvious for all likely readers of that instruction: if the reader is able to reliably figure out an omitted step in a few seconds - then this step does not belong to the instruction.
However if the step is obvious only for some readers and is not obvious for other readers - then such step should be included into the instruction (because it is much more time consuming to figure out non-obvious step than to skip obvious instruction steps).

Understand your goals
Another important consideration when writing instructions - is to clearly understand the purpose of the instruction. I knew why I needed that instruction:
1) To help developers on my team to quickly familiarize themselves with setting up Hyper-V VMs.
2) In the future - to remind me and other developers key steps we used in creating our VMs.
3) To have a source file that we can edit to reflect key choices in configuration of our VM.

K. did not have these goals in mind and, actually, thought that such "VM setup" instruction is useless, but puffed up the instruction anyway. According to his belief - all instructions must be written in such a way that even a dummy would be able to follow it. The mistake here is to assume that the dummy (who does not know how to navigate a wizard) would actually read our instruction.
dennisgorelik: (Default)
About half a year ago Samsung released two pretty fast SSDs:
Samsung 960 EVO
$479.99 for 1TB

Samsung 960 PRO
$579.99 for 1TB

As you can see, PRO version is exactly $100 more expensive than EVO.

Does it worth?

According to specification:
960 EVO sequential read is up to 3.2GB/second.
960 PRO sequential read is up to 3.5GB/second.

However the reality is about 40% slower than advertising specification:
On my home server I got about 2GB/second sequential read for 960 EVO, and about 1.8 GB/second for 960 PRO.

To benchmark my SSDs I copied several files with ~80GB size into nul in Far Manager.

I used this motherboard (which is quite modern):
ASUS Motherboard, (PRIME Q270M-C/CSM)


Do you know what could be the reason why I cannot get promised 3.2 GB/second?
And why PRO has slower performance than cheaper EVO?

I even swapped PRO and EVO between NVMe slots on my motherboard, but the results were consistent: PRO was slower than EVO.

Update (thanks to mugunin):
Finally the benchmark that looks similar to what I measured (sequential read):
In our 2MB sequential benchmark, the Samsung 960 EVO recorded the best results in read with 2,308.5MB/s—even beating out the 960 Pro. On writes, it came in second with 1,660.9MB/s, only losing to the Pro version.


dennisgorelik: (Default)
Dennis Gorelik

September 2017

34567 8 9
1011 12131415 16


RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Sep. 23rd, 2017 05:47 am
Powered by Dreamwidth Studios