|
>
 Saturday, April 18, 2009
 |
|
 |
|
|
|
|
|
A new CTP was released for .NET Services in March and as I update my Access Control Service (ACS) samples to reflect changes I thought I might post the relevant changes here to save all 5 of you devoted blog readers some time. First off, the ACS has a new certificate, which means your web sites and WCF services that rely on ACS tokens must update their configuration to reflect the new thumbprint. The old thumbprint was 416e6fa5d982b096931fbf42c4a3dcd608856c95, and the new thumbprint is 6DE1689A739D548A5690DBC3894B953EF6123D93. So, if you provide trusted issuers in configuration, your <microsoft.identityModel> configuration must be updated to reflect this: <microsoft.identityModel> <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry"> <trustedIssuers> <add name=http://{yoursolutionname}.accesscontrol.windows.net thumbprint="6DE1689A739D548A5690DBC3894B953EF6123D93"/> </trustedIssuers> </issuerNameRegistry> ...more settings </microsoft.identityModel> If your trusted issuers are handled with a custom IssuerNameRegistry component, you might do something like this: <issuerNameRegistry type="TrustedIssuerNameRegistry"/> and the component: public class TrustedIssuerNameRegistry : IssuerNameRegistry { public override string GetIssuerName(SecurityToken securityToken) { X509SecurityToken x509Token = securityToken as X509SecurityToken; if (x509Token != null) { if (String.Equals(x509Token.Certificate.Thumbprint, "6DE1689A739D548A5690DBC3894B953EF6123D93")) { return x509Token.Certificate.SubjectName.Name; } } throw new SecurityTokenException("Untrusted issuer."); } } Another change is the issuer URI format for your hosted STS. What used to be: http://accesscontrol.windows.net/{yoursolutionname} is now http://{yoursolutionname}.accesscontrol.windows.net. Although this may not be an exhaustive list since likely every place you use your solution URI you will have to update this...here are some things I had to update related to the ACS: 1. Declarative trusted issuer entries (this value is used when the ClaimsPrincipal is generated, as the issuer for those claims): <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry"> <trustedIssuers> <add name=http://{yoursolutionname}.accesscontrol.windows.net thumbprint="6DE1689A739D548A5690DBC3894B953EF6123D93"/> </trustedIssuers> </issuerNameRegistry> 2. Addressing your passive STS URI, which in this example is the URI for passive federation with Live ID (I am told this will later change to Federation.aspx for all passive federation URI): <microsoft.identityModel> <federatedAuthentication enabled="true"> <wsFederation passiveRedirectEnabled="true" issuer=https://{yoursolutionname}.accesscontrol.windows.net/passivests/LiveFederation.aspx realm="http://localhost/PassiveACSWebSite" reply="http://localhost/PassiveACSWebSite/Default.aspx" ></wsFederation> </federatedAuthentication> </microsoft.identityModel> 3. I have a custom Saml11SecurityTokenHandler that validates that any ACS tokens are from MY solution and not other solutions signed with the same private key. You do this by checking the token's Issuer property as shown in my custom type. Below is the configuration to add the custom token handler and the implementation. <microsoft.identityModel> <securityTokenHandlers> <remove type="Microsoft.IdentityModel.Tokens.Saml11.Saml11SecurityTokenHandler, Microsoft.IdentityModel, Version=0.5.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <add type="SecurityExtensions.ACSSamlTokenHandler, SecurityExtensions"/> </securityTokenHandlers> </microsoft.identityModel> public class ACSSamlTokenHandler: Saml11SecurityTokenHandler { private string Issuer { get; set; } public ACSSamlTokenHandler() : this(new SamlSecurityTokenRequirement()) { } public ACSSamlTokenHandler(SamlSecurityTokenRequirement samlSecurityTokenRequirement): base(samlSecurityTokenRequirement) { } public ACSSamlTokenHandler(XmlElement customConfiguration): base(customConfiguration) { } private void Initialize() { if (MicrosoftIdentityModelSection.Current != null) { IssuerNameRegistryElement trustedIssuersConfig = MicrosoftIdentityModelSection.Current.IssuerNameRegistry; string s = trustedIssuersConfig.ElementAsXml.ToString(); } } public override Microsoft.IdentityModel.Claims.ClaimsIdentityCollection ValidateToken(System.IdentityModel.Tokens.SecurityToken token) { if (token == null) throw new ArgumentNullException("token"); SamlSecurityToken samlToken = token as SamlSecurityToken; if (samlToken == null) throw new ArgumentException(string.Format("Argument cannot be null: {0}", "token")); if (!samlToken.Assertion.Issuer.Contains("http://{yoursolutionname}.accesscontrol.windows.net")) { throw new SecurityTokenException(string.Format("The token issuer {0} is not expected.", samlToken.Assertion.Issuer)); } return base.ValidateToken(token); } } So if you are updating ACS samples, this may come in handy. Cheers!
|
|
|
 |
|
 |
 Friday, April 17, 2009
 |
|
 |
|
|
|
|
|
Well, almost immediately following the tutorials I delivered at SD West and Dev Connections in March, many of the CTPs that I discussed were updated...and so I had to find some time to get my docs updated to reflect the changes. I have finally pulled it together. This post will provide machine setup used for my technology roadmap seminar as of April 2009. Since many of these are CTP technologies, everything is subject to change…some things sooner than later. Here is a link to a document with the setup links below, in addition to reference materials on each technology. http://www.dasblonde.net/downloads/idesigntechnologyroadmapresourcesv3.doc I am still working on testing the azure samples with new CTPs before posting the zip with code here. Will update this post with a link. Platform Setup These instructions assume you are running on Windows Vista SP1 or Windows Server 2008. This section describes core machine setup for the operating system, .NET 3.0, SQL Server and Visual Studio. - Enable IIS, ASP.NET and WAS features
- SQL Server 2005/2008 or SQL Express 2005/2008
- Install any service packs
- Visual Studio 2008 SP1 (also installs .NET Framework 3.5 SP1)
- Windows SDK for Windows Server 2008 (really, this SDK is for .NET Framework 3.5 and is also supported on Vista, XP/SP2 and Windows Server 2003)
F# - F# (September 2008 CTP)
- F# Interactive Console
- F# Samples
- F# Web Tools
Parallel Computing - Parallel Extensions to the .NET Framework 3.5 (June 2008 CTP)
Entity Framework - ADO.NET Entity Framework Extensions
Velocity - Windows PowerShell 1.0 (required for Velocity installation)
- Microsoft Project Code Named “Velocity” Community Technology Preview 3 (CTP3)
WPF - Expression Studio 2 Trial
ASP.NET - AJAX 4.0 Preview 4
- ASP.NET MVC 1.0
Silverlight - Silverlight Tools for VS 2008 SP1 (installs Silverlight 2 SDK and Silverlight 2 runtime)
- Silverlight 2 SDK (already installed with Silverlight Tools for VS SP1)
- Silverlight Toolkit
WCF Identity Platforms Azure Services Platform - Windows Azure SDK (March 2009 CTP)
- Windows Azure Tools for Visual Studio (March 2009 CTP)
- Microsoft .NET Services SDK (March 2009 CTP)
- Access Control Service
- Documentation
- MMC Tool
- Azure Management Tools
- Windows Live ID Client 1.0 SDK (October 2008)
- Windows Live ID Delegated Authentication SDK 1.2 (November 2009)
- Windows Live ID Web Authentication SDK 1.2 (November 2009)
- Windows Live Tools for Visual Studio (November 2008)
- Live Services SDK
|
|
|
 |
|
 |
 Tuesday, March 31, 2009
 |
|
 |
|
|
|
|
|
The Open Cloud Manifesto is live at http://www.opencloudmanifesto.org. I wrote my opinion of it prior to its release based on some concerns that were already voiced in the community. Now, I get to comment on the real thing. On the one hand, the manifest is described as trying to bring about a core set of principles around cloud computing for vendors to agree to and users to count on. The problem is that the set of principles was decided by a group that doesn't include three of the biggest players in the cloud today: Google, Amazon and Microsoft. I am babbled at how a group can get together and form a manifesto like this without first including these major players in its definition. This has already started off badly and doesn't say much for the credence people will place in the manifesto going forward. I think the biggest problem with the manifesto is its discussion of interoperability and portability. It isn't clear to me what are the interoperability goals for this manifesto. If interoperability means that a cloud vendor can't provide a service to its customers that is not based on standards such as HTTP, WS* and REST...I say why not? Hey, if I want to use a set of functionality exposed a protocol other than HTTP isn't that up to me, the customer? What if that particular set of functionality happens to be useful to my application? What if I don't require interoperable standards for all communications between moving parts of my application? Let me decide what is best, thank you. If my goal is to be able to move my application to another platform (next topic = portability) then I won't consider this option...but I may not care! The manifesto doesn’t directly target a specific vendor – but it does indicate some unreasonable goals, specifically related to application portability and vendor lock-in. Vendor lock-in is a frequently discussed anti-pattern that describes the problem where customers cannot easily move their applications from one platform to another without significant cost and effort. Avoiding vendor lock-in is at odds with the benefits a specific vendor can provide with its own brand of unique features and productivity tools. The pros and cons of vendor lock-in have been debated for a decade now. Attempts to remove vendor lock-in with J2EE failed in my opinion. One of the goals of the J2EE platform was to enable customers to port from one vendor to another without pain – but I can tell you from first-hand experience this is not easy to accomplish. Each vendor supplies additional features and tools that make you more productive and effective if you use them. In fact, part of the decision to purchase a J2EE platform is these extended features. You have to explicitly avoid using extended features if you want to be truly portable. But why lose productivity to build a product just so you can move it to another platform? This is a good question…if this is a priority to your business, you will pay up front in development effort and associated cost to enable portability. If time to market, productivity and cost saving is a priority and you trust the vendor, you’ll happily forego portability. My point is that ultimately the decision to make an application completely portable or to rely on a rich set of vendor-specific features and tools is up to the customer. The Open Cloud Manifesto principles are essentially discouraging (if not disallowing) vendors from producing any features or platform tools that are not offered by another cloud vendor. This is very simply NOT ok. If we expect cloud vendors to produce completely homogenous hosting environments with identical programming APIs then we stifle the creativity of each vendor. Each vendor should be free to supply a unique set of features and platform tools to form its own value proposition. Perhaps one cloud vendor will provide better productivity than another because of such features and tools – and this benefits the customer. The Open Cloud Manifesto should focus on much more important matters such as the details vendors should produce in a Service Level Agreement (SLA) for their customers. This includes describing how the equipment, data, applications and all other assets are secured; describing their topology for load balancing and fail over; describing how they handle backup and recovery of applications and data; describing how they meter, monitor and report on this data; and describing how deployments and updates managed. Some of these things can be standardized, others are just guidelines for what a good cloud vendor should do to be trustworthy. Ok, that's just my opinion...let's see where it goes. In the meantime, Google, Amazon and Microsoft - keep doing what you are doing...we like the diversity of options and we are grown-ups so we can decide which platform works best for our needs.
|
|
|
 |
|
 |
 Monday, March 30, 2009
 |
|
 |
|
|
|
|
|
I just returned from Dev Connections held in Orlando, Florida...so here is my usual post-conference blog entry. I delivered my Microsoft Technology Roadmap tutorial and 6 sessions. The list is below, with links to code samples and other related content. Don't forget to check the readme for some of these downloads since it includes setup information such as required CTPs that I may have been using. Email me with any questions. Microsoft Technology Roadmap Tutorial - I updated my "technology avalanche" tutorial to reflect today's long list of things we should care about including F#; parallel computing; technologies related to data access, windows, web, SOA and workflow; new security platforms; model-driven development with Oslo and cloud computing. Whew! Following this post will be a separate blog entry dedicated to this session and all the resources you need to get set up to work with these technologies and reference it from here.
- Update: 04/17/09
Building RIAs with AJAX, Silverlight and WCF - In this session I focused on how you design WCF services for AJAX and SL 2, what issues to consider, and how to consume them. If you are looking for how to do SOAP, POX or REST with RIAs, look at these samples. If you want pretty UI, you're in the wrong place!!!! Just the facts man!
- Here are the RIA samples: http://www.dasblonde.net/downloads/RIASamples.zip
- Some of my RESTful WCF samples were illustrated: http://www.dasblonde.net/downloads/RESTfulWCF.zip
- This site includes a MessageInspectors sample that handles faults for Silverlight 2 clients.
- This site includes the ASP.NET AJAX 4.0 Preview 4, and related code samples that illustrate the next generation code for communicating with services and data binding (among other things).
Choosing the Right Data Access Technology - As if there weren't a big enough avalanche of technologies across the board, just in data access there are many, and so this session really focused on when, where and how I would use each from the classic DataSet and DataReader, to LINQ to SQL, Entity Framework and ADO.NET Data Services. Mostly architectural diagrams and discussion, but here is a link to the code samples I presented: http://www.dasblonde.net/downloads/DataAccessSamples.zip
Federated Security Scenarios with WCF and Geneva Framework - I wrote two MSDN articles on this subject which have links to the sample code as well:
-
WS* or REST? Choosing the Right Approach for your WCF Services Securing Workflow Services .NET Synchronization Techniques for Today's Applications - This was a beginner session we added to the fundamentals track at Dev Con. I did demos on the fly mostly, how to kick off multiple threads using custom threads, delegates, asynchronous patterns with WCF proxies and the new Task Parallel Library (TPL) and Parallel LINQ (PLINQ). Then I also showed some synchronization techniques, again on the fly.
- Take a look at my Windows Forms hosting samples in my WCF book code for lots of synchronization examples. All of my code samples for my book can be downloaded from here: http://www.thatindigogirl.com. Be sure to download the VS 2008 code.
- In addition, see my TPL/PLINQ samples in the code for my roadmap tutorial (see above).
|
|
|
 |
|
 |
 Saturday, March 28, 2009
 |
|
 |
|
|
|
|
|
Recently, I discovered that my code samples using MicrosoftAjaxDataService.js no longer worked on my new machine. I had assumed that .NET Framework 3.5 SP1 included the new AJAX-y things I was using before it - that were part of ASP.NET 3.5 Extensions. I was wrong...but as I searched around I could only find blog posts using the MicrosoftAjaxDataService.js file, with no reference as to where it was now! I finally stumble upon the fact that it was renamed to MicrosoftAjaxAdoNet.js and is now part of ASP.NET AJAX 4.0 Preview 4. So, now your scripts to include are as follows: <asp:ScriptManager ID="ScriptManager1" runat="server"> <Scripts> <asp:ScriptReference Name="MicrosoftAjax.js" Path="~/scripts/MicrosoftAjax.js" /> <asp:ScriptReference ScriptMode="Inherit" Path="~/scripts/MicrosoftAjaxTemplates.js" /> <asp:ScriptReference ScriptMode="Inherit" Path="~/scripts/MicrosoftAjaxAdoNet.js" /> </Scripts> </asp:ScriptManager> And, there is a new DataContext (for WCF services) and an AdoNetDataContext (for data services). Not to mention some REALLY cool new binding features that will greatly simplify how we handle results from service calls...nice! I never really did want to revisit my DHTML days... Here is a link to ASP.NET AJAX 4.0 Preview 4: http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24645 I hope this blog entry helps at least a few people find the "new way". Cheers!
|
|
|
 |
|
 |
 Friday, March 27, 2009
 |
|
 |
|
|
|
|
|
There is some buzz going on related to an Open Cloud Manifesto. Microsoft and Amazon are not (yet) active participants...(ahem) two of the major cloud computing players...and there is already a bit of skepticism brewing. Who is driving this manifesto? Who are they trying to benefit if they aren't involving Microsoft and Amazon early on? Why is it a secret until published this coming Monday? Without seeing it first-hand it is hard to comment in detail. However, my gut tells me that a group got together wanting to beat others to forming a cloud-focused organization supposedly for the community’s benefit. This group wants ownership of the process, like a new OASIS or WS-I, so they (big mistake) tried to come up with a plan before showing Amazon, Microsoft and perhaps others – expecting them to be bullied into signing, instead of coordinating their early participation. Perhaps they were afraid they could not “run the show” if they showed their cards too early? Who knows. Clearly Amazon and Microsoft are in agreement that they will not sign this manifesto “as-is”. Where is Google in this? I’m skeptical that there needs to be a manifesto in the first place. Bottom line is companies will innovate and expose APIs, services and hosting capabilities as they see fit to win customers. They will provide SLAs that are either acceptable or not. They will either succeed or not based on their ability to deliver on their promises for 24/7 monitoring, uptime, deployment and management capabilities, features, and fair billing practices. Do we need a manifesto to tell companies how to do business? Where was the manifesto for companies that how our web sites? Where were they when I hosted my site with a vendor that went out of business and lost my files? Could a manifesto have helped me choose a better host? As I said, cloud computing vendors will succeed or fail based on the value of what they offer to "their community" and how well they follow through. Do all vendors need to be grouped into a limited set of cloud computing requirements that could stifle innovation for a specific user base? Do all vendors have to price the same way? Should all of their SLAs be identical? I think not. I think that what WOULD be helpful is community guidance on what are good practices for cloud computing. There is a summary of a Cloud Computing Bill of Rights (see link below) already available. The problem is it that it currently sounds like they are trying to dictate what an SLA must provide, and how pricing should work (among other things) and it sounds almost like it will be used as ammunition for punitive actions. That is just wrong. I'll say it again: cloud computing vendors will succeed or fail by their own hand. There doesn't need to be outside governance to force Amazon, Microsoft or others to produce a decent SLA, pricing policy, safe hosting environment or valuable feature set. It would be better to guide the community on things that they should look for in an SLA to feel comfortable hosting applications with a cloud vendor. No different than what I am already doing having written my share of 60 page SLAs for applications in my charge. Of course cloud computing is supposed to (among other things) make hosting applications more accessible for small businesses that can't hire an IT staff to manage 24x7 operations, and that can't afford to provision enough machines for period peak loads. Businesses should not just host and forget, however...they must still monitor how the provider is doing. This is where some education comes in...for it can be more difficult to know what to look for in an SLA to trust hosing with another company, and it can be difficult to know how to monitor how the vendor is doing. What we do know is that a cloud computing vendor can probably do a better job with their dedicated resources for hosting, failover, load balancing, peak load provisioning, and so forth. We need great SLAs, competitive pricing models, and follow through. I seriously doubt a manifesto is necessary to achieve this. I’m missing the value proposition of this manifesto so far. I will be interested to read what the initial manifesto looks like. The details aren't clear at all from the current buzz. Some links:
|
|
|
 |
|
 |
 Thursday, March 19, 2009
 |
|
 |
|
|
|
|
|
I just returned from SD West, a conference a speak at each year in Santa Clara. Here I delivered several tutorials and sessions, many embracing new subject matter that excites me lately. The list of tutorials and sessions are below. I am a little behind schedule here as I am just now in the process of posting links to the code for each session. See links and comments below. Email me with any questions. Microsoft Technology Roadmap Tutorial - I updated my "technology avalanche" tutorial to reflect today's long list of things we should care about including F#; parallel computing; technologies related to data access, windows, web, SOA and workflow; new security platforms; model-driven development with Oslo and cloud computing. Whew! I will post a separate blog entry dedicated to this session and all the resources you need to get set up to work with these technologies and reference it from here.
- Update: 04/17/09
-
Cloud Computing with the Azure Services Platform Tutorial A Lap Around Geneva Framework - One of my favorite subjects - federated security!
- I wrote two MSDN articles on this subject which have links to the sample code as well:
Access Control Service: Federated Security in the Cloud - Another favorite, all things federated!
- UPDATE: 05/21/09
- Due to forthcoming changes in the ACS platform my article on the subject is delayed until later this year, so you should look to the SDK for now.
WS* or REST? Choosing the Right Approach for your WCF Services Architectural Scenarios for Workflow Services
|
|
|
 |
|
 |
 |
|
 |
|
|
|
|
|
As the press has been discussing these past days, Windows Azure had an outage on the weekend. I provided some comments to the press and was quoted here: http://www.crn.com/software/215900816 Only a few of my remarks made it into the article, so I thought I would provide here a complete picture of my comments on this issue. My message to the press, and to the community is that I don't think Microsoft should be judged harshly on this incident, but because they are Microsoft and people are watching...they probably need to kick it up a notch and act like they are already a production service - to inspire trust. It is that simple. They didn't do anything wrong, but people will take notice and therefore it is important. What is it they say? Dress for the job you want, not the job you have? Here is my summary of the situation: One question people might have is one of service levels and uptime guarantees. Right now, the Windows Azure platform is a CTP, not even a Beta product yet, so I don’t measure them against Salesforce.com or Amazon. I don't expect them to provide me with any service levels since there is not yet a service level agreement in place for services rendered. I do expect them to try not to have outages, and I do expect them to respond to outages quickly - and I think they are doing this. Last weekend's problem occurred from a routine update, recovery took longer than expected but they acted immediately. I think the only mistake Microsoft made is not notifying the Azure account holders in advance that an update would be performed, in the event of something failing. This is an easy thing to do that will inspire confidence and trust. Now, let’s put this into perspective. On the one hand, Microsoft is doing the community a great service by allowing access to Azure during this CTP phase of development. This also helps Microsoft immensely as the community will provide feedback on the platform which will influence the features and functionality of the final release. This is a really good thing. On the other hand, because they are live, CTP or not people will judge Microsoft now. I am hosting my own test projects with Azure, and I don’t like it when they are down, but I am a realist – I am using a CTP. I have no doubts about Microsoft’s ability to host a 24/7 operation and meet acceptable service levels when Azure is a production service. However, not everyone will see it this way. This is a new space for Microsoft – hosting applications and services – and the community is watching closely. They may not be ready to produce an SLA, for this requires significant legal review as well, but they can at least give prior notice of downtime and the expected duration of that downtime. Or, if unexpected downtime occurs, immediately inform the community via emails to Azure account holders. Keeping people well informed of planned outages in the future would also be helpful. In a word – “communicate”. I expect that Microsoft will in future avoid downtime altogether by performing rolling updates of the system so that our hosted applications are not affected as machines are updated. My understanding is that their data centers are being set up to handle this when Azure goes live. In the meantime, one recommendation Microsoft provides is that we deploy multiple instances of each role (Web Role, Worker Role) so that there is redundancy and less risk of impact if there is another incident. Microsoft will certainly be incorporating feedback from this incident and ongoing Azure CTP usage into their production release. To the community I say “it is a CTP, don’t worry, just give feedback on what you would have expected”. To Microsoft I say “try to put production-worthy notifications and rolling updates in place now to avoid negative opinions on the CTP basis”.
|
|
|
 |
|
 |
 Friday, November 21, 2008
 |
|
 |
|
|
|
|
|
I recently presented at Dev Connections in Las Vegas - a few of my favorite WCF-related topics including routing, performance and scalability, and federated security of course! This post contains links to the latest code samples that I demonstrated in the session. VWC303: Building a WCF Router for Your Applications - I wrote a few articles for MSDN earlier this year that might be helpful:
- My latest routing code is here:
VWC305: Practical Scenarios for Federated Security - I wrote several articles describing my utilities for pre-Geneva federation with WCF:
- I have two articles to be published in MSDN Magazine related to Geneva. See December and January issues. These are also posted online but I don't have a link yet.
- The code from my book includes my pre-Geneva federated security samples.
- My Geneva samples are posted here:
- I will have more Geneva samples to post in a few weeks. I am working on updating my pre-Geneva claims-based samples to use Geneva Framework and in the process will provide updates to my utilities that will help you migrate to Geneva Framework more seamlessly. You can expect a blog post on this specifically.
VWC304: Load Balancing and Scaling Your WCF Services - For my ASP.NET Pro column on WCF, I wrote two articles for the December and January issues - the first on load balancing and scalability issues, the second on dealing with SSL load balancing routers such as F5 / BigIP. You can view the most recent 3 issues at any time here:
- Sample code from the talk includes the following:
|
|
|
 |
|
 |
|
|
ON THIS PAGE
|
|
|
|
SEARCH
|
|
|
|
CATEGORIES
|
|
|
|
ARCHIVES
|
| | Sun | Mon | Tue | Wed | Thu | Fri | Sat | | 29 | 30 | 31 | 1 | 2 | 3 | 4 | | 5 | 6 | 7 | 8 | 9 | 10 | 11 | | 12 | 13 | 14 | 15 | 16 | 17 | 18 | | 19 | 20 | 21 | 22 | 23 | 24 | 25 | | 26 | 27 | 28 | 29 | 30 | 1 | 2 | | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|
|
BLOGROLL
|
|
|
|
|
 |
|