Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
putin is a cunt
Apr 5, 2007

BOY DO I SURE ENJOY TRASH. THERE'S NOTHING MORE I LOVE THAN TO SIT DOWN IN FRONT OF THE BIG SCREEN AND EAT A BIIIIG STEAMY BOWL OF SHIT. WARNER BROS CAN COME OVER TO MY HOUSE AND ASSFUCK MY MOM WHILE I WATCH AND I WOULD CERTIFY IT FRESH, NO QUESTION

JawnV6 posted:

No. They are an hour apart. One happens, then an hour goes by, and the second happens. They share a label, that doesn't magically collapse the space/time continuum between those events.

Sorry I think you're right, I wasn't noticing the "Z" on the end of those strings.

Adbot
ADBOT LOVES YOU

crashdome
Jun 28, 2011
There is definitely some debate as to whether there is data loss there. I think it's not so much the problem with the DateTime structure as much as how it initializes the DateTime from the parsed string. Sure, the strings are two different values in UTC time but, if it parses both to local using a method similar as such:

code:
2015-11-01T06:00:00Z  --becomes-->  format [int yr, int mon, int day, int hr, int min, int sec]   --as local values-->  [2015, 11, 1, 1, 0, 0]
2015-11-01T07:00:00Z  --becomes-->  format [int yr, int mon, int day, int hr, int min, int sec]   --as local values-->  [2015, 11, 1, 1, 0, 0]

var dst = new DateTme(2015, 11, 1, 1, 0, 0);
var nondst = new DateTme(2015, 11, 1, 1, 0, 0);
var result = (dst == nondst);  //True
what is the problem? Of course they are equal. Is there really data loss if we are working in a local time zone?

whereas what some (I think) are expecting that this instead happens :


code:
2015-11-01T06:00:00Z  --becomes-->  format [int yr, int mon, int day, int hr, int min, int sec]  --as UTC values-->  [2015, 11, 1, 6, 00, 0]
2015-11-01T07:00:00Z  --becomes-->  format [int yr, int mon, int day, int hr, int min, int sec]  --as UTC values-->  [2015, 11, 1, 7, 00, 0]

var dst = new DateTme(2015, 11, 1, 6, 0, 0, DateTimeKind.UTC);
var nondst = new DateTme(2015, 11, 1, 7, 0, 0 DateTimeKind.UTC);
var result = (dst == nondst); //False
which is because the DateTime is initialized in a non-DST time zone (UTC in this case) but, this also assumes local conversion is done AFTER initializing the DateTime.

Interestingly, I wonder if this is the case with the second scenario if we added this as the next line?:

code:
var resultLocal = (dst.ToLocalTime() == nondst.ToLocalTime())  //True???
Edit: Whelp..


Edit2: Also had to adjust times to accommodate real DST for me

I guess the moral of the story is that DateTime is really just a label and not really reliable.
The more I think about it, the more I can see the behavior as something to be expected.

crashdome fucked around with this message at 02:22 on Sep 18, 2015

chippy
Aug 16, 2006

OK I DON'T GET IT
How come VS2013 doesn't have the same refactoring options for VB as it does to C#. Extract Method, for example, is missing.

if I go here: https://msdn.microsoft.com/en-us/library/ckfya594(v=vs.120).aspx

There's mention of something called Refactor! which is supposedly available, but clicking the link takes me somewhere talking about free trials.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

Bognar posted:

The example I provided shows that's not true, information is lost since 1:30AM when DST ends is ambiguous. The only way to avoid this with DateTime is with your third suggestion - specify to parse as UTC (or with RoundTripKind).

Sedro posted:

C# code:
var dst = TimeZoneInfo.ConvertTimeToUtc(DateTime.Parse("2015-11-01T05:30:00Z"));
var nonDst = TimeZoneInfo.ConvertTimeToUtc(DateTime.Parse("2015-11-01T06:30:00Z"));

I was wrong, the second option also works which means that information is not being lost. Now, the question I have is why does the equality return true if they're referring to different points in time?

Mr Shiny Pants
Nov 12, 2012

Bognar posted:

I was wrong, the second option also works which means that information is not being lost. Now, the question I have is why does the equality return true if they're referring to different points in time?

The strings are both equal length? ;)

gariig
Dec 31, 2004
Beaten into submission by my fiance
Pillbug

Bognar posted:

I was wrong, the second option also works which means that information is not being lost. Now, the question I have is why does the equality return true if they're referring to different points in time?

I believe Jon Skeet goes over most of this in a blog post. However, it comes down to the Kind property on the DateTime object.

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Bognar posted:

I was wrong, the second option also works which means that information is not being lost. Now, the question I have is why does the equality return true if they're referring to different points in time?

Because they are the same time according to the hosed up, wrong-headed bullshit that is the Daylight Savings Time system.

chippy
Aug 16, 2006

OK I DON'T GET IT
I have a Func(TFoo, IENumerable(Of TBar)) being passed into a method. I can use it to a get a Foo's collection of Bar's by passing the Foo into the Function. So, I'd be passing in something like Function(f) f.Bars

Thing is, I also want to assign a new collection of Bar's to the property as well. Can I do this? Or do I need to be passing in an Expression or something instead?

Google Butt
Oct 4, 2005

Xenology is an unnatural mixture of science fiction and formal logic. At its core is a flawed assumption...

that an alien race would be psychologically human.

The settings + event function worked perfectly., thanks dudes. If anyone wants a super lightweight launcher for twitch streams using that liverstreamer thing, let me know :)

chippy
Aug 16, 2006

OK I DON'T GET IT

chippy posted:

I have a Func(TFoo, IENumerable(Of TBar)) being passed into a method. I can use it to a get a Foo's collection of Bar's by passing the Foo into the Function. So, I'd be passing in something like Function(f) f.Bars

Thing is, I also want to assign a new collection of Bar's to the property as well. Can I do this? Or do I need to be passing in an Expression or something instead?

addendum: Basically, I want to check if Foo.Bars is Null or not, and assign a new List of Bars if it is. But the property name and type itself may change.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy
Two options that I can think of:

1. Add another parameter to the function of type Action(TFoo, IEnumerable(Of TBar)) that you can use as a setter.
2. Change the type of the Func parameter to Expression(Func(TFoo, IEnumerable(Of TBar))) and get the property info from the MemberExpression, then use GetGetMethod and GetSetMethod to get and set the property.

Option 1 is easier to write, option 2 is easier to use. If you need more info on 2 I can go into greater detail.

chippy
Aug 16, 2006

OK I DON'T GET IT

Bognar posted:

Two options that I can think of:

1. Add another parameter to the function of type Action(TFoo, IEnumerable(Of TBar)) that you can use as a setter.
2. Change the type of the Func parameter to Expression(Func(TFoo, IEnumerable(Of TBar))) and get the property info from the MemberExpression, then use GetGetMethod and GetSetMethod to get and set the property.

Option 1 is easier to write, option 2 is easier to use. If you need more info on 2 I can go into greater detail.

Thanks. I came up with something similar to #2. Just leaving work now, put I'll post it up on Monday, as wouldn't mind some feedback, there's probably a more elegant way of doing it than what I came up with.

ljw1004
Jan 18, 2005

rum

chippy posted:

How come VS2013 doesn't have the same refactoring options for VB as it does to C#. Extract Method, for example, is missing.

We finally overhauled the refactorings in VS2015. Now there are more refactorings, and VB has them all too, and it's actually even possible to write your own refactorings if you want using something called "Roslyn Analyzers".

Also VS2015 is faster at compiling VB code.

Horn
Jun 18, 2004

Penetration is the key to success
College Slice

Google Butt posted:

The settings + event function worked perfectly., thanks dudes. If anyone wants a super lightweight launcher for twitch streams using that liverstreamer thing, let me know :)

I've been meaning to code something up for this so I'm interested in whatever you have.

Google Butt
Oct 4, 2005

Xenology is an unnatural mixture of science fiction and formal logic. At its core is a flawed assumption...

that an alien race would be psychologically human.

Speaking of which, I'm stuck again. I'm trying to add a pop-up triggered by a button that will launch the streamer's chat. I've gotten so far as to launch a second window with a frame and webbrowser inside of it using this line in the second window's code:

code:
frame.Source = new Uri("http://www.twitch.tv/username/chat", UriKind.Absolute);
I currently have a textbox in the parent window, in which the user inputs the streamer's username, that username is taken and inserted into a cmd command on button click:

code:
procInfo.Arguments = "/C livestreamer twitch.tv/" + stream_path.Text
I'm trying to figure out how to take that same input and insert it into that frame.Source string (where username is) so that the frame.Source changes automatically and launches the correct chat via another button. I'm probably going about this all wrong, any help is appreciated.

Google Butt fucked around with this message at 22:39 on Sep 19, 2015

Google Butt
Oct 4, 2005

Xenology is an unnatural mixture of science fiction and formal logic. At its core is a flawed assumption...

that an alien race would be psychologically human.

Google Butt posted:

Speaking of which, I'm stuck again. I'm trying to add a pop-up triggered by a button that will launch the streamer's chat. I've gotten so far as to launch a second window with a frame and webbrowser inside of it using this line in the second window's code:

code:
frame.Source = new Uri("http://www.twitch.tv/username/chat", UriKind.Absolute);
I currently have a textbox in the parent window, in which the user inputs the streamer's username, that username is taken and inserted into a cmd command on button click:

code:
procInfo.Arguments = "/C livestreamer twitch.tv/" + stream_path.Text
I'm trying to figure out how to take that same input and insert it into that frame.Source string (where username is) so that the frame.Source changes automatically and launches the correct chat via another button. I'm probably going about this all wrong, any help is appreciated.

Took all day but I figured it out. Feels good. Here it is for whoever wants it.. stores your previous inputs and it will open the chat of your streamer. The chat uses roughly 4 times the memory of MPC-HC with a stream at source quality, but that's still half the memory and 1/10th the cpu usage of Firefox at source quality. The chat uses the IE wrapper, still ends up being half the usage of the Firefox popout chat.

Not a lot in the grand scheme of things, but if you want to play a high cpu usage game and watch a stream at the same time, saving 10-20% cpu usage can be nice!

Edit: For those of you with really a low spec pc/laptop or want to reduce your cpu/mem usage even further, going from source to high halves that.

Google Butt fucked around with this message at 23:31 on Sep 20, 2015

chippy
Aug 16, 2006

OK I DON'T GET IT

chippy posted:

Thanks. I came up with something similar to #2. Just leaving work now, put I'll post it up on Monday, as wouldn't mind some feedback, there's probably a more elegant way of doing it than what I came up with.

So, this is what I came up with. By the way, the purpose of the method is something completely different, the checking of the property for null and assigning it a new collection if it is null, is just something it incidentally needs to do (quite a lot of times) but I've removed all the stuff unrelated to this.

code:
Public Function DoAThing(Of TFoo, TBar)(barCollectionExpression As Expression(Of Func(Of TFoo, List(Of TBar)))) As List(Of TFoo)

    ' Use Bar collection getter expression to create Barcollection setter expression
    Dim parameter = Expression.Parameter(GetType(List(Of TBar)), "p")
    Dim assignmentExpression As Expression(Of Action(Of TFoo, List(Of TBar))) =
        Expression.Lambda(Of Action(Of TFoo, List(Of TBar)))(Expression.Assign(childCollectionExpression.Body, parameter), childCollectionExpression.Parameters(0), parameter)

    ' Use expression to create getter and setter functions
     Dim getFunction As Func(Of TFoo, List(Of TBar)) = childCollectionExpression.Compile()
     Dim setFunction As Action(Of TFoo, List(Of TBar)) = assignmentExpression.Compile()

    'Do a bunch of stuff, during which we (lots of times) need to check a Bar for its collection of Foos, and create one if it lacks it

    If getFunction(oneOfOurFoos) Is Nothing Then
        setFunction(oneOfOurFoos, New List(Of TMany))
    End If

    Return listOfFoos
End Function
This is working, and is fairly easy to use now it's written, but how terrible is it exactly? And why?

edit: called like this:

code:
    DoAThing(Function(foo) foo.Bars)

chippy fucked around with this message at 09:09 on Sep 21, 2015

chippy
Aug 16, 2006

OK I DON'T GET IT
To be honest, I don't completely understand the line that creates assignmentExpression (thanks SO) so I'd love if someone could explain that to me.

e: And by the way, the actual aim was to create a generic implementation of the method given here: https://www.tritac.com/bp-24-dapper-net-by-example under 'A parent object with its child objects'.

chippy fucked around with this message at 10:41 on Sep 21, 2015

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy
If you're only going one level deep, (e.g. foo.Bars, not foo.Bar.Bazzes) then you could simplify it a bit by using PropertyInfo. I've put an example together here: https://dotnetfiddle.net/9j3BS3

In your code, the assignment expression line is programmatically creating a function that does this:

Visual Basic .NET code:
Sub(foo As TFoo, p As List(Of TBar)) [expression(foo)] = p
where [expression(foo)] is whatever Expression<Func<TFoo, List<TBar>>> that you passed in. Expression.Assign is the part that generates [expression(foo)] = p and Expression.Lambda is what turns that assignment expression into a function expression, i.e. wrapping it with Sub(foo As TFoo, p As List(Of TBar)). Compile() turns those expressions into actual functions that you can call.

Bognar fucked around with this message at 16:00 on Sep 21, 2015

epswing
Nov 4, 2003

Soiled Meat
From last page:

epalm posted:

What's grinding my gears is SQL Server and C# do different things by default. Which project manager allowed that one?

ShimaTetsuo posted:

Probably the same one who allowed the same discrepancy between the rounding in Excel and in Excel-VBA. Microsoft get your poo poo TOGETHER

What's really crazy is that using decimal.Round(decimal, int) in C# uses MidpointRounding.ToEven by default, HOWEVER using the same function call in a C# linq query executed on SQL Server ultimately uses MidpointRounding.AwayFromZero. So it's more than just "SQL Server does this by default, C# does that by default". It's "your C# code uses a different MidpointRounding depending on the context" :derp:

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

epalm posted:

What's really crazy is that using decimal.Round(decimal, int) in C# uses MidpointRounding.ToEven by default, HOWEVER using the same function call in a C# linq query executed on SQL Server ultimately uses MidpointRounding.AwayFromZero. So it's more than just "SQL Server does this by default, C# does that by default". It's "your C# code uses a different MidpointRounding depending on the context" :derp:

Yeaahhh, but things get weird when you deal with IQueryable and SQL since the Expression code isn't being run, just parsed and transformed. This also results in string.Contains or string.Equals being case insensitive and other minor differences.

brap
Aug 23, 2004

Grimey Drawer
These kinds of things are pretty much inevitable if you want c# code to basically compile into SQL at runtime and execute in your database. It's amazing they've made it as close as it is to the "real thing."

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

fleshweasel posted:

These kinds of things are pretty much inevitable if you want c# code to basically compile into SQL at runtime and execute in your database. It's amazing they've made it as close as it is to the "real thing."

That's why I love FSharp.Data.SqlClient so much. Give me the type safety and otherwise just let me write straight SQL: it's easier (and far, far more useful) to learn to write good SQL than to learn the quirks of an ORM's DSL.

Mr Shiny Pants
Nov 12, 2012

NihilCredo posted:

That's why I love FSharp.Data.SqlClient so much. Give me the type safety and otherwise just let me write straight SQL: it's easier (and far, far more useful) to learn to write good SQL than to learn the quirks of an ORM's DSL.

Fsharp's Type providers are pretty awesome compared to an ORM. Though I do like PetaPoco for data access in C#.

RICHUNCLEPENNYBAGS
Dec 21, 2010

epalm posted:

From last page:



What's really crazy is that using decimal.Round(decimal, int) in C# uses MidpointRounding.ToEven by default, HOWEVER using the same function call in a C# linq query executed on SQL Server ultimately uses MidpointRounding.AwayFromZero. So it's more than just "SQL Server does this by default, C# does that by default". It's "your C# code uses a different MidpointRounding depending on the context" :derp:

Since we're complaining -- string.Compare, string concatenation? Come on. Also if you can write DbFunctions.TruncateTime(someDate) you really should be able to write someDate.Date too.

At the very least it would be nice if there were an easy way to verify that an expression could be translated that didn't involve just running it.

Polio Vax Scene
Apr 5, 2009



Is there a way in visual studio to check a project for all uses of any enums? I'm having serialization problems with them, but its not just one specific enum, and I have a few hundred of them to sort out (tool generated).

Essential
Aug 14, 2003
What options are available for security when connecting a web service to a remote MySQL database, specifically on the web service side? Because I'm not aware of any. I have a client who is finally starting to get serious about security so they bought and installed an SSL cert and now only allow secure connections to their database.

My knowledge on this is that security lies entirely on their end by: implementing SSL and restricting users to only the db/tables/roles that are needed. I have implemented SslMode=Required into my connection string, but I have no idea what else they expect me to do.

However, their IT guy is insistent that I must implement security measures on my end and I'm really at a loss on what to do. The connection string is stored in web.config (not encrypted). He sent me there PEM cert file for their SSL, which they've already implemented to secure connections coming into their server, I'm trying to explain that I don't need the cert but he thinks I do.

Am I missing something obvious/important here that I really do need to do?

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

Manslaughter posted:

Is there a way in visual studio to check a project for all uses of any enums? I'm having serialization problems with them, but its not just one specific enum, and I have a few hundred of them to sort out (tool generated).

Do a find/replace over the declaration page for "public enum " -> "public enum BUTTS_", then go through the error list?

(Also known as the "wow girl these hammer-shaped glasses are really makin' you look thin and sharp" method.)

Funking Giblet
Jun 28, 2004

Jiglightful!

Manslaughter posted:

Is there a way in visual studio to check a project for all uses of any enums? I'm having serialization problems with them, but its not just one specific enum, and I have a few hundred of them to sort out (tool generated).

Write a unit test or something with the below code.


code:
 Assembly.GetAssembly(typeof (SomeTypeInAssembly))
                        .GetTypes()
                        .Where(x => x.IsEnum && x.IsPublic)
Adjust to taste.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug
Other options:

- Code Lens
- Architecture tools (code map, dependency graph)
- Parse codebase with Roslyn, spit crap out to console/file/whatever

putin is a cunt
Apr 5, 2007

BOY DO I SURE ENJOY TRASH. THERE'S NOTHING MORE I LOVE THAN TO SIT DOWN IN FRONT OF THE BIG SCREEN AND EAT A BIIIIG STEAMY BOWL OF SHIT. WARNER BROS CAN COME OVER TO MY HOUSE AND ASSFUCK MY MOM WHILE I WATCH AND I WOULD CERTIFY IT FRESH, NO QUESTION
We're really struggling to get something working and I hope someone here has some ideas. We have a product that we sell that needs to support Firebird and SQL Server. We're developing a new product for those same customers, so it also needs to support both. I'm wondering how on Earth I could possibly get this to work with Entity Framework? We came up with the bright idea of including two SSDLs and swapping them out in the connection string, depending on what database type they were using. This works well enough except the Firebird SSDL generated by Visual Studio is incorrect - it maps the database types incorrectly. I suspect this is ultimately the fault of Firebird's dodgy Entity Framework Provider. I was hoping, though I know it's unlikely, that someone here has some experience with this - we've been beating our heads against this particular wall all day and we're getting nowhere.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy
No experience with Firebird whatsoever, but if it comes down to it you can try to fix the bugs in their EF provider:

http://sourceforge.net/p/firebird/NETProvider/ci/master/tree/NETProvider/src/

EssOEss
Oct 23, 2006
128-bit approved

Essential posted:

Am I missing something obvious/important here that I really do need to do?

Set goals, define the attack vectors you want to defend against, plan the security approach. Just throwing security measures at the wall is better than nothing but I recommend you have a sit-down with your client and talk through what the purpose of this is and then figure out the appropriate steps to tackle it.

Essential
Aug 14, 2003

EssOEss posted:

Set goals, define the attack vectors you want to defend against, plan the security approach. Just throwing security measures at the wall is better than nothing but I recommend you have a sit-down with your client and talk through what the purpose of this is and then figure out the appropriate steps to tackle it.

Good point and that's effectively what the conversation I had with them turned into. What they are ultimately after is secure connections to their server and db users having the minimum rights necessary to do what they need to.

raminasi
Jan 25, 2005

a last drink with no ice
I'm trying to implement basic validation on some cells in a WPF DataGrid, and I'm having trouble. To start I'm just trying to get the straightforward default red box around a cell if the user enters a non-numeric value in a field that needs to be numeric, but the red box isn't showing up. My reading of How to: Implement Validation with the DataGrid Control seems to be that all I need to do is define the DataGrid column like <DataGridTextColumn Header="Value" Binding="{Binding Value, ValidatesOnDataErrors=True}" />, but it's not working. Googling this is really hard because apparently the problem most people have is that they want to get rid of the red box, not figure out why it's missing.

I know that the setter is failing when the input is wrong - I can see the correct exception being thrown when I have a debugger attached, and when there's invalid cell contents, you can't edit any other cell.

EssOEss
Oct 23, 2006
128-bit approved
There are two possibilities for validation: ValidatesOnExceptions and ValidatesOnDataErrors. You mention an exception, so perhaps you are trying to use the latter with exceptions, instead of the former? The latter requires you to implement the IDataErrorInfo interface and is generally the way I would recommend you go, as exceptions are of very limited practical usefulness due to their inflexibility (e.g. you cannot really handle interdepentent validation of data fields).

Che Delilas
Nov 23, 2009
FREE TIBET WEED

GrumpyDoctor posted:

I'm trying to implement basic validation on some cells in a WPF DataGrid, and I'm having trouble. To start I'm just trying to get the straightforward default red box around a cell if the user enters a non-numeric value in a field that needs to be numeric, but the red box isn't showing up. My reading of How to: Implement Validation with the DataGrid Control seems to be that all I need to do is define the DataGrid column like <DataGridTextColumn Header="Value" Binding="{Binding Value, ValidatesOnDataErrors=True}" />, but it's not working. Googling this is really hard because apparently the problem most people have is that they want to get rid of the red box, not figure out why it's missing.

I know that the setter is failing when the input is wrong - I can see the correct exception being thrown when I have a debugger attached, and when there's invalid cell contents, you can't edit any other cell.

I don't have a specific answer for you, but if you continue to have problems with the DataGrid control, consider using a ListView with its built-in GridView style instead. I'm pretty sure DataGrid is a holdover from the old style of data binding (binding a control directly to an ADO DataTable/DataSet so as to allow users to directly read and update database values :gonk:) and when I was working with WPF/MVVM I had no end of problems getting it to look and behave the way I wanted. I found the listview much easier to work with and customize.

Uziel
Jun 28, 2004

Ask me about losing 200lbs, and becoming the Viking God of W&W.
This is a long shot, but does anyone use SqlChangeMonitor for cache subscription/invalidation? We switched to it recently, are getting deadlocks and now our generally performant queries are slow when the server is under load.

Gul Banana
Nov 28, 2003

query notification is slow and interferes with MVCC
https://msdn.microsoft.com/en-us/library/ms187528.aspx explains the limitations. the short version is, don't use it unless the db is not a bottleneck.

Adbot
ADBOT LOVES YOU

Uziel
Jun 28, 2004

Ask me about losing 200lbs, and becoming the Viking God of W&W.

Gul Banana posted:

query notification is slow and interferes with MVCC
https://msdn.microsoft.com/en-us/library/ms187528.aspx explains the limitations. the short version is, don't use it unless the db is not a bottleneck.
Thanks, that's helpful. I'm gathering info to convince my coworkers to immediately move away from it.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply