Тёмный

C# Debugging and Clean Up - A TimCo Retail Manager Video 

IAmTimCorey
Подписаться 415 тыс.
Просмотров 13 тыс.
50% 1

Bugs happen. Tracking down bugs is a major skill to learn as a developer. In this video, we are going to track down a couple of subtle bugs and squash them. We will also fix a couple of nagging issues to make the application work just that little bit better.
** TimCo source code now at: www.iamtimcorey.com/courses/b...
Full Courses: www.iamtimcorey.com
Mailing List: signup.iamtimcorey.com/
One-off tutorials are awesome but they aren't the only thing you should be doing to learn C#. Another vital part of learning is learning how to put it all together. This interactive course is all about putting the pieces together. You can watch each video on its own or you can watch them in order and see a bigger picture. The choice is yours.
This course focuses on real-world development. As such, we are simulating that we work for TimCo Enterprise Solutions on a brand new product, the TimCo Retail Manager. Just like in the real world, we are starting out with one set of requirements but know that over time they will change.

Опубликовано:

 

7 июл 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 107   
@chrishuerta2506
@chrishuerta2506 5 лет назад
Tim hasn't even started the conversion to .net core and I have learned so much! Thanks Tim!
@IAmTimCorey
@IAmTimCorey 5 лет назад
Excellent!
@eastonronan18
@eastonronan18 3 года назад
i know I am kinda randomly asking but does anybody know a good place to watch newly released movies online?
@apolloeli5693
@apolloeli5693 3 года назад
@Easton Ronan Try Flixzone. Just search on google for it =)
@asherernest1625
@asherernest1625 3 года назад
@Apollo Eli yup, I've been using Flixzone for since march myself :D
@eastonronan18
@eastonronan18 3 года назад
@Apollo Eli thanks, I signed up and it seems like a nice service :D Appreciate it !
@bicentrick9989
@bicentrick9989 5 лет назад
Hi tim great video as always .. the stuff i learn here are enormous ..the world needs more people like you.
@IAmTimCorey
@IAmTimCorey 5 лет назад
I appreciate the kind words.
@codingwithgyver1637
@codingwithgyver1637 3 года назад
Your process of eliminating bugs here are awesome sir Tim.
@IAmTimCorey
@IAmTimCorey 3 года назад
Glad it was helpful!
@harag9
@harag9 4 года назад
Another great episode, many thanks for this and the course. Much appreciated!
@IAmTimCorey
@IAmTimCorey 4 года назад
You are welcome.
@djangounchained7314
@djangounchained7314 4 года назад
Great!! during all this crazy Corona times its the best time to keep moving on !!!
@IAmTimCorey
@IAmTimCorey 4 года назад
If you are able to take advantage of the time, that's great. Just don't feel bad if you struggle too.
@XentonR
@XentonR 3 года назад
Hi Tim, I've just finished this video. This course is aswome! I think I've learned more in a week than during the 2-year-long vocational software developer school. I noticed a thing. It's not a bug , but could be useful regarding the remove function. We can only remove the items 1 by 1. Maybe it could be cool if we were able to remove more than 1 item. I mean the item's quantity. I don't know if this has already been implemented in the future videos, there is a lot to catch up to the current state. If it is already done, just ignore this comment. :) I was experimenting with removing the items from the cart, based on the item quantity, but when I add back the quantity to the existing items it would generate plus items. E.g. you add to the cart 5 Skillet from the existing 20 and you want to remove 6, you will end up having 21 skillet. I know I could fix it with an If statement, but I don't want to be off the track. I want to follow this series as precisely as I can, since I'm re-learning the C# with You right now. Thanks for the amazing content!
@tomthelestaff-iamtimcorey7597
@tomthelestaff-iamtimcorey7597 3 года назад
A huge part of developing to learning to debug those problems. Great job!
@sebastiandhom7172
@sebastiandhom7172 3 года назад
Hi again, the quantity field isn't updated after a checkout. Well, its updated after adding something to the cart. But when for whatever reason a user will change the resetted 1 to 100, then the 100 will still stay in the qty field. Just set ItemQuantity = 1; in our ResetSalesViewModel() after reinit the Cart property. Cheers Sebastian
@siddgoen
@siddgoen 3 года назад
One suggestion for handing the NotifyPropertyChange for multiple fields on adding, removing or clearing items from cart. Instead of adding set of NotifyOfPropertyChange for different properties in AddToCart, RemovingFromCart, ClearCart, we can create an eventhandler for the Cart.ListChanged event and add all the NotifyOfPropertyChange calls for all the dependent fields in this handler function. This way, whenever there is any change in the Cart list, these notify events will be called. Cart.ListChanged += Cart_ListChanged; private void Cart_ListChanged(object sender, ListChangedEventArgs e) { NotifyOfPropertyChange(nameof(CanCheckOut)); NotifyOfPropertyChange(nameof(CanRemoveFromCart)); NotifyOfPropertyChange(nameof(SubTotal)); NotifyOfPropertyChange(nameof(Tax)); NotifyOfPropertyChange(nameof(Total)); }
@tomthelestaff-iamtimcorey7597
@tomthelestaff-iamtimcorey7597 3 года назад
Thanks for sharing the tip.
@Baraka-yl2dp
@Baraka-yl2dp 4 года назад
Tim, you spoke about adding Barcode reader functionality in this presentation. I think this will be a valuable addition. And like you said, it should not be a difficult addition. It will, however, be difficult when you try to do so by writing generic code that will accept any type of barcode reader. In other words, you write the code such that you don't need any specific barcode reader drivers from any specific manufacturer. If you can't do that, then you will be stuck with writing code for specific manufacturers, which will not be an attractive solution since you would prefer your users to just use any barcode reader, even the cheap ones from China that usually do not come with any device drivers. I would be very much interested in seeing how you go about writing generic code to accept any barcode reader. Best regards,
@IAmTimCorey
@IAmTimCorey 4 года назад
Actually, barcode readers typically are just keyboard inputs. When you scan a barcode, it "types" the barcode value quickly. Usually there isn't any custom code around them.
@Fizzle372
@Fizzle372 5 лет назад
for the LogOffUser you can use some reflection :) foreach (var property in GetType().GetProperties()) { property.SetValue(this, default); }
@IAmTimCorey
@IAmTimCorey 5 лет назад
I could, although I try to avoid reflection if I can help it.
@andywalter7426
@andywalter7426 5 лет назад
@@IAmTimCorey However, automapper uses reflection though too. I would think if you wanted to avoid reflection, then instead of using reflection, you would have to use the same method to copy from one class to another.
@IAmTimCorey
@IAmTimCorey 5 лет назад
Automapper uses reflection differently. It does it once at the start of the application (on configuration). It then uses that map to do the actual translations. It is more efficient than typical uses of reflection. Basically, you get a small startup hit and then you have great performance. The case above is different in that you would use reflection each time you logged off. While I do avoid reflection, I don't totally ban its use. Automapper is an example of when I do use it but also how I use it sparingly (I wouldn't use Automapper if it were a constant drain whenever I mapped an object).
@andersonsolutions4u
@andersonsolutions4u 5 лет назад
Hi Tim, I actually started watching your videos before I decided to go to school. Love your videos. They chose Java for a couple classes. Any suggestions for Java skills?
@IAmTimCorey
@IAmTimCorey 5 лет назад
I'm sorry, I don't have any specific suggestions. In general, practice whatever you learn. Don't skip the practice because you understand something. Build small applications to practice what you learned. That makes a HUGE difference in how well you learn something and it exposes your assumptions in your learning.
@andywalter7426
@andywalter7426 5 лет назад
@@IAmTimCorey Any suggestions on small applications to even create.
@jjloco315
@jjloco315 5 лет назад
Like always awesome videos. Your videos are very informative. I was wondering in your following videos or so or just a simple video I’m creating an application for school but like to use MVVM C# by having a top and bottom panel and a bottom initiate when pressed the top panel will slide to the bottom and the bottom panel will slide up. Then save the state of the panels when opening and closing the panel. If any body can help that’s awesome as well. Thanks.
@IAmTimCorey
@IAmTimCorey 5 лет назад
That's a bit more than can be explained in a comment. In general, break down the issue into small pieces and get one piece at a time to work.
@brandonparkinson3924
@brandonparkinson3924 3 года назад
Hi Tim, wondering if you can help me. Been following along. When I check the data in the dbo.Sale table, all of the 'Subtotal', 'Tax', and 'Total' fields show '4.2613', regardless of which items I select and regardless of their quantity, any idea why this may be happening? fixed - I had sale.Total = sale.SubTotal = sale.Tax; and I should have had sale.Total = sale.SubTotal + sale.Tax;
@timothywestern6488
@timothywestern6488 4 года назад
I'm now thinking of the possibilities of more than one register open. When checkout occurs, we probably need to verify that the amount in inventory is still available for each item before processing the sale. (This would be a good example of a typical racing condition, where one user gets to it before the other.) Although I can imagine this might not happen often in a store that sells hands on product, in a virtual sense maybe it could.
@IAmTimCorey
@IAmTimCorey 4 года назад
We will definitely be taking that into account. Thanks!
@objectaware5296
@objectaware5296 5 лет назад
@31:36 There is a method introduced into a data model I would instead create a UserLoggedIn property. private bool _userLoggedIn = false; public bool UserLoggedIn { set { if(value == false) { Token = Id = FirstName = LastName = EmailAddress = string.Empty; CreatedDate = DateTime.MinValue; } _userLoggedIn = value; } get { return _userLoggedIn;} } Add this statement to the GetLoggedInUserInfo after the assignment of the token value. _loggedInUser.UserLoggedIn = true; Also, get in the habit of using string.Empty instead of "" By using string.Empty you're ensuring that the correct value is being used for the executing platform. If you're assigning the same value to multiple variables in a model using an assignment inline will save a lot of typing. Token = Id = FirstName = LastName = EmailAddress = string.Empty;
@99MrX99
@99MrX99 5 лет назад
I heard that best practices is, that setting properties should not cause any action (e.g which causes changes to other public properties). That would happen here. For that methods should be used instead.
@objectaware5296
@objectaware5296 5 лет назад
@@99MrX99 That does not make logical sense. Whether I do the actions in a method or another property the consequences are the same. Why I would choose the property over the method is that it is a data model and not a class lib. I believe Tim was also concerned about using a method in this model, at least I thought he eluded to that starting @29:55 - @30:48 Making it a property makes life so much easier also. When the authentication is done it initializes the model data at TRMDesktopUI.Library.ApiHelper.ApiGetLoggedInUserInfo the UserLoggedIn property is set to true. All the code used at TRMDesktopUI.ViewModels.ShellViewMode.IsLoggedIn is reduced to a simple property check _user.UserLoggedIn. To log the user out simply set the property to false _user.UserLoggedIn = false; There are many scenarios, where setting one property causes the setting of default values of other properties. I hope my reasoning makes sense if not please let me know.
@IAmTimCorey
@IAmTimCorey 5 лет назад
I agree with Alex. Limit your property logic to gated input and output (restricting how much data is returned, what data is stored, etc.) If you need more logic than that, move it to a method.
@objectaware5296
@objectaware5296 5 лет назад
@@IAmTimCorey I'm going to respectfully disagree. It is a common practice to have one property, especially one that is conditional, e.g. IsXXXX, to load or initialize other properties of the class. If there is any correction I would make to my comment it is to the naming of the property, it should be "IsUserLoggedIn" Also, I don't understand the use of the term "gated" in the segment "... gated input and output...". Nothing gates this model class.
@jimkoro664
@jimkoro664 4 года назад
Hi Tim. Appreciate your great work! A question. Would it be eventually better to have a Method in the ApiHelper to Clear the LoggedInUser for us (where we already have access to the ILoggedInUser) instead of adding a Method to a Model Class?
@IAmTimCorey
@IAmTimCorey 4 года назад
I'll think about it. Thanks for the suggestion.
@ferooref7614
@ferooref7614 4 года назад
Damn cool series Tim. I was thinking about what if the token expires ? That way the "IsLoggedIn" prop wont work properly. What would be the solution for that ? Do u create "/api/is-logged-in" endpoint ?
@IAmTimCorey
@IAmTimCorey 4 года назад
We will get to that. It won't allow you to access the protected resources anymore, which will throw an error.
@WolfJustWolf
@WolfJustWolf 5 лет назад
at 26:30 could it be that your method is just calling itself, and just keeps doing that ?
@IAmTimCorey
@IAmTimCorey 5 лет назад
Yep, duh! :-) I should have caught that.
@Jason-Woolf
@Jason-Woolf Год назад
I know I'm like 3 years behind but . . . at 20:44 when we are working on the ResetSalesViewModel method we do "Cart = new BindingList();" couldn't we just do "Cart.Clear()" this is better for readability and probably speed/resources?
@darenmartin5292
@darenmartin5292 Год назад
Both ways seem like acceptable solutions
@onyebuchiboss
@onyebuchiboss 4 года назад
Thank you very much Tim. I got a question, you are resetting the ProductDisplayModel Cart to its initial products and Quantity, arent we meant to update the API with the current status of List, rather resetting it to its intial status ? I think this is where the inventory databse comes into play ?
@IAmTimCorey
@IAmTimCorey 4 года назад
Right now the inventory is not being updated properly. Once we get that part put in place, we will get the actual values instead of the essentially static values.
@StudentCompanion
@StudentCompanion 5 лет назад
Hi Tim. Thanks for the great video again. Is the source code for this video already on Patreon? I can't find it.
@IAmTimCorey
@IAmTimCorey 5 лет назад
Sorry about that. I was setting up a bunch of content before I left for my vacation and I missed that one. I just uploaded it.
@StudentCompanion
@StudentCompanion 5 лет назад
@@IAmTimCorey Thanks
@cqli7981
@cqli7981 3 года назад
Hi, Tim. After we checkout, should we update the product quantity in stock in database? if user has purchased 1 product, the number in stock of this product would be -1, right? Thank you
@IAmTimCorey
@IAmTimCorey 3 года назад
We will do that eventually, yes.
@girornsveinsson7970
@girornsveinsson7970 4 года назад
I have a bug that is probably also in the official code in that if I log out and try to log in again I get the following error: "cannot add value because header 'authorization' does not support multiple values". It seems like I can fix this by moving IntializeClient() from the constructor in APIHelper to the beginning of the Authenticate method. Is that OK?
@IAmTimCorey
@IAmTimCorey 4 года назад
I don't think that's a good idea. I believe this is because when you are logging out, the values from the header aren't being cleared out. Make sure to clear the headers upon logout and when assigning new headers.
@gus9822
@gus9822 4 года назад
Hi . I love you videos . I have one or two questions . 1. This solution will work also with SQLite? is the same approach ? or will be a harder on implementation ? 2. What do you think about Fody/property change nuget package? thanks and keep up the good work !
@IAmTimCorey
@IAmTimCorey 4 года назад
It depends on what you mean by "work with SQLite". The SQL project will not create a SQLite database so you will need to do that manually. However, the code will all work with SQLite with only two small tweaks: you need to change the connection string and the Dapper code to connect to the database needs to reference SQLite instead of SQL (just a difference in NuGet package and one line for each method). As for Fody, it seems like a good plugin.
@webfactorysolutions
@webfactorysolutions 5 лет назад
Hi Tim, quick question, I noticed that there's another channel with your videos but just called "visual studio" is this channel also yours or are they impersonating you? If it's yours, what's the difference between both? That aside, your videos have been very well and simple explained, and obviously very helpful, thanks a lot for that and keep up the awesome work!!
@IAmTimCorey
@IAmTimCorey 5 лет назад
I believe it is a channel where someone stole my videos and is trying to get views using them. I'm working on getting it taken down.
@webfactorysolutions
@webfactorysolutions 5 лет назад
@@IAmTimCorey dam, that's low, you're doing and awesome work, and and thanks for all that you do, let me know if you need a link or if I can help somehow
@jrichardw
@jrichardw 5 лет назад
Hi Tim...do you have a course on dialogs using caliburn micro? I see a few approaches out there but I like how you code with mvvm. Id like to see how you would do a dialog service (or something simpler) using caliburn micro.
@LudwigMurilloEngineer
@LudwigMurilloEngineer 5 лет назад
This video explains it. by the same author by the way ru-vid.com/video/%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE-laPFq3Fhs8k.html
@IAmTimCorey
@IAmTimCorey 5 лет назад
There you go. Dialogues are a pain in WPF. Essentially, you need to create your own or "cheat" by calling a WinForm dialog.
@jrichardw
@jrichardw 5 лет назад
Thanks guys. I'll check this out!
@volcousa
@volcousa 5 лет назад
Thank you for the video! I had a question rolling around for a bit.. It's a little out of the subject but I hope you could answer it! Is it possible to display data on a website from a database without having to refresh the webpage or pressing any buttons?
@IAmTimCorey
@IAmTimCorey 5 лет назад
You mean that you want a real-time update of the data? Yes, that is possible. Typically, you would do that with JavaScript making calls to an API periodically. If you needed real-time (not at certain intervals), you could use a tool like SignalR.
@volcousa
@volcousa 5 лет назад
@@IAmTimCorey I'll look into it! Thank you very much!
@catarinaruna5085
@catarinaruna5085 5 лет назад
Forgive me for this silly irrelevant question, but I wonder if anyone knows the name of the font at the start of the video where it says CODE WITH ME. Thank you
@IAmTimCorey
@IAmTimCorey 5 лет назад
Kalam Light
@dimasprasetya9267
@dimasprasetya9267 4 года назад
Hi Tim, Why don't we update the QuantityInStock of products after we Checkout? I mean in the database. So, after we do ResetSalesViewModel, the Products have an up to date Quantity.
@IAmTimCorey
@IAmTimCorey 4 года назад
I can't remember. I think we are going to in the future once we get the inventory set up properly but I am not positive.
@dimasprasetya9267
@dimasprasetya9267 4 года назад
@@IAmTimCorey hahaha Ok Tim, I forgot that this tutorial has made in the last year
@objectaware5296
@objectaware5296 5 лет назад
Once you check out the inventory is reduced by the purchased amounts. Yet the refresh of the products comes back with the pre-check out values - it is not calling the API to get the updated inventory.
@IAmTimCorey
@IAmTimCorey 5 лет назад
Actually it is calling the API for the inventory but we aren't updating the inventory in SQL when we make a sale. That is on the todo list to get that all straightened out and working correctly.
@objectaware5296
@objectaware5296 5 лет назад
@@IAmTimCorey I may be confused but I thought we called the API to check the inventory, price and to set the sale in the database? Just checked and we do we just don't adjust for the sale.
@timothywestern6488
@timothywestern6488 4 года назад
@@IAmTimCorey just saw this, ignore my comment.
@charlesabell5382
@charlesabell5382 4 года назад
Hi Tim this video got me thinking about the login events. Is there anyway to login when the enter/return key is pressed while focus is on the password box?
@IAmTimCorey
@IAmTimCorey 4 года назад
Yep, you can attach to that event.
@charlesabell5382
@charlesabell5382 4 года назад
So I ended up playing around with this and found in the View that setting the button property to IsDefault="True" works as intended. Is there any gotcha to this approach? Should I be looking at attaching differently to a KeyDown="" event instead? I can get at the attached event code behind but can't figure out how to attach it to the button LogIn method.
@tklingborg
@tklingborg 4 года назад
I noticed that you can remove more items than you have in the cart from the cart. I've tried to find a solution for it but I'm still new at this so no luck so far.
@IAmTimCorey
@IAmTimCorey 4 года назад
Interesting. I don't think I can do that in my code but I can check. It should be that once you remove the last item, the button is no longer enabled.
@piotrc966
@piotrc966 5 лет назад
LogOut method should clear DefaultRequestHeaders of HttpClient because it keeps valid token.
@IAmTimCorey
@IAmTimCorey 5 лет назад
Good catch! I'll add that in the next video.
@scottgodfrey7855
@scottgodfrey7855 5 лет назад
By setting the cart to a new instance of a cart, won't that cause a memory leak? The original cart is still there, but a new cart has been created. With the original instance of the cart still having the items in it., that might stop the dispose method from automatically disposing that instance.
@IAmTimCorey
@IAmTimCorey 5 лет назад
It is only there if something still has a reference to it. Since nothing does, the old object gets marked for disposal. Even though there were valid items in the cart instance we destroyed, that will not keep the cart instance from being destroyed.
@99MrX99
@99MrX99 5 лет назад
@@IAmTimCorey you could also call Cart.Clear() instead, so you don't need to create a new instance and is much shorter and also updates the UI and another point, we could use an auto propery without setter and without backing field
@IbrahimMohammad2023
@IbrahimMohammad2023 5 лет назад
Hello Tim .. thank u for your tutorials ... I have a question..what about xamarin course ?
@bicentrick9989
@bicentrick9989 5 лет назад
i believe he said in one of his videos that he's just getting into it, maybe he'll start doing tutorials once he finishes with this one
@IAmTimCorey
@IAmTimCorey 5 лет назад
Yep, Xamarin is coming but I've got a lot of ground I need to cover in a lot of areas (.NET Core, desktop .NET Core, Blazor, Xamarin, microservices, etc.)
@onyebuchiboss
@onyebuchiboss 4 года назад
This very course could be implemented using Xamarin as the frontend, with just a few difference (because xamarin is .net core). I am using xamarin as my UI rather than WPF.
@farveshrahim8457
@farveshrahim8457 3 года назад
Hello Tim! Im getting empty values when i use the ILoggedInUser in shellView model. Even though it sets values in AuthenticatedUser class. And the Token value is also null could you please help me figure out why that is? Thanks.
@IAmTimCorey
@IAmTimCorey 3 года назад
Step through the code step by step from where you know it is working and identify where the data goes missing.
@bberrevoets
@bberrevoets 3 года назад
Hello , Have you found the problem? Because i have the same problem and even after 2 days of stepping trough, i still cant't find the solution.
@zeevsolomonik6162
@zeevsolomonik6162 3 года назад
Hey, did you find the problem eventually? I just stepped into it to realize that the _user is empty.
@markdekuijer
@markdekuijer 4 года назад
how far is this course complete? I know you said in the first episode that it depends on comments ect... But i prefer to have a full course ready to watch instead of waiting 2 weeks for an new episode. could anyone tell me in short how far we are and what you learned till this episode?
@IAmTimCorey
@IAmTimCorey 4 года назад
There is a playlist with all of the videos from this course in it. We are currently on video 23 and the next one will come out Friday.
@roycelithgo3968
@roycelithgo3968 4 года назад
If you Log off with something in the Cart, next time you login the Cart is not empty. I fixed this by making ResetSalesViewModel() public and then calling that from LogOut in ShellViewModel. Not sure if this is the cleanest way. public async Task LogOut() { _user.LogOffUser(); await _salesVM.ResetSalesViewModel(); ActivateItem(IoC.Get()); NotifyOfPropertyChange(() => IsLoggedIn); }
@IAmTimCorey
@IAmTimCorey 4 года назад
Thanks for pointing that out. I'll put this on the list of things to address.
@ivandrofly
@ivandrofly 5 лет назад
What did you use for DI?
@IAmTimCorey
@IAmTimCorey 5 лет назад
SimpleContainer, which is built into Caliburn Micro. We will use Autofac for the API at some point probably. Here is the info on SimpleContainer: caliburnmicro.com/documentation/simple-container
@Saeefar
@Saeefar 2 года назад
Not working, Account Menu Not showing when login
@darenmartin5292
@darenmartin5292 Год назад
Change FallbackValue = Visible
@runtimeterror4027
@runtimeterror4027 3 года назад
How to be a patron
@IAmTimCorey
@IAmTimCorey 3 года назад
Thanks for considering ways to help me keep making FREE content for my students. Its folks like you that support me via Patreon and purchasing paid courses that enable the free content to reach more people. Patreon: patreon.com/IAmTimCorey Newsletter signup: signup.iamtimcorey.com/ Thank you.
@kevinmerrell9952
@kevinmerrell9952 Год назад
Some profit would be nice. Why else would you sell stuff?
@IAmTimCorey
@IAmTimCorey Год назад
Yep.
Далее
Еду за гитарой…
01:00
Просмотров 263 тыс.
Conquering fears and slippery slops on two wheels!
00:18
Yeni Özbək Mahnisi Yoxsa Vefali Reqsi? 😍
00:36
Просмотров 2,1 млн
Managing User Roles - A TimCo Retail Manager Video
1:12:42
Early Refactoring in C# - A TimCo Retail Manager Video
40:41
Kubernetes 101 workshop - complete hands-on
3:56:03
Просмотров 1,6 млн
Integrate REAL Camera Data in Your 3D Scenes!
3:49:41
Просмотров 812 тыс.
Bjarne Stroustrup: C++ | Lex Fridman Podcast #48
1:47:13
Еду за гитарой…
01:00
Просмотров 263 тыс.