text:
//-----------------------------------------------------------------------
// <copyright file="CheckoutController.cs" company="Sitecore Corporation">
//     Copyright (c) Sitecore Corporation 1999-2015
// </copyright>
//-----------------------------------------------------------------------
// Copyright 2015 Sitecore Corporation A/S
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//       http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
// -------------------------------------------------------------------------------------------

namespace Sitecore.Commerce.Storefront.Controllers
{
    using Sitecore;
    using Sitecore.Commerce.Connect.CommerceServer.Orders.Models;
    using Sitecore.Commerce.Connect.DynamicsRetail.Entities.Carts;
    using Sitecore.Commerce.Contacts;
    using Sitecore.Commerce.Entities.GiftCards;
    using Sitecore.Commerce.Entities.LoyaltyPrograms;
    using Sitecore.Commerce.Entities.Payments;
    using Sitecore.Commerce.Entities.Shipping;
    using Sitecore.Commerce.Storefront.Managers;
    using Sitecore.Commerce.Storefront.Managers.Storefront;
    using Sitecore.Commerce.Storefront.Models.InputModels;
    using Sitecore.Commerce.Storefront.Models.JsonResults;
    using Sitecore.Commerce.Storefront.Models.Storefront;
    using Sitecore.Diagnostics;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Mvc;
    using MCC = Sitecore.Commerce.Storefront.Constants.CartConstants;

    /// <summary>
    /// Handles all calls to checkout
    /// </summary>
    public class CheckoutController : BaseController
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CheckoutController" /> class.
        /// </summary>
        /// <param name="cartManager">The cart manager.</param>
        /// <param name="orderManager">The order manager.</param>
        /// <param name="loyaltyProgramManager">The loyalty program manager.</param>
        /// <param name="accountManager">The account manager.</param>
        /// <param name="paymentManager">The payment manager.</param>
        /// <param name="shippingManager">The shipping manager.</param>
        /// <param name="giftCardManager">The gift card manager.</param>
        /// <param name="storeManager">The store manager.</param>
        /// <param name="contactFactory">The contact factory.</param>
        public CheckoutController([NotNull] CartManager cartManager,
            [NotNull] OrderManager orderManager,
            [NotNull] LoyaltyProgramManager loyaltyProgramManager,
            [NotNull] AccountManager accountManager,
            [NotNull] PaymentManager paymentManager,
            [NotNull] ShippingManager shippingManager,
            [NotNull] GiftCardManager giftCardManager,
            [NotNull] StoreManager storeManager,
            [NotNull] ContactFactory contactFactory)
            : base(contactFactory)
        {
            Assert.ArgumentNotNull(cartManager, "cartManager");
            Assert.ArgumentNotNull(orderManager, "orderManager");
            Assert.ArgumentNotNull(loyaltyProgramManager, "loyaltyProgramManager");
            Assert.ArgumentNotNull(accountManager, "accountManager");
            Assert.ArgumentNotNull(paymentManager, "paymentManager");
            Assert.ArgumentNotNull(shippingManager, "shippingManager");
            Assert.ArgumentNotNull(giftCardManager, "giftCardManager");
            Assert.ArgumentNotNull(storeManager, "storeManager");

            this.CartManager = cartManager;
            this.OrderManager = orderManager;
            this.LoyaltyProgramManager = loyaltyProgramManager;
            this.AccountManager = accountManager;
            this.PaymentManager = paymentManager;
            this.ShippingManager = shippingManager;
            this.GiftCardManager = giftCardManager;
            this.StoreManager = storeManager;

            if (Sitecore.Context.User.IsAuthenticated)
            {
                CurrentVisitorContext.ResolveCommerceUser(accountManager);
            }
        }

        /// <summary>
        /// Gets or sets the cart manager.
        /// </summary>
        /// <value>
        /// The cart manager.
        /// </value>
        public CartManager CartManager { get; protected set; }

        /// <summary>
        /// Gets or sets the payment manager.
        /// </summary>
        /// <value>
        /// The payment manager.
        /// </value>
        public PaymentManager PaymentManager { get; protected set; }

        /// <summary>
        /// Gets or sets the shipping manager.
        /// </summary>
        /// <value>
        /// The shipping manager.
        /// </value>
        public ShippingManager ShippingManager { get; protected set; }

        /// <summary>
        /// Gets or sets the order manager.
        /// </summary>
        /// <value>
        /// The order manager.
        /// </value>
        public OrderManager OrderManager { get; protected set; }

        /// <summary>
        /// Gets or sets the loyalty program manager.
        /// </summary>
        /// <value>
        /// The loyalty program manager.
        /// </value>
        public LoyaltyProgramManager LoyaltyProgramManager { get; protected set; }

        /// <summary>
        /// Gets or sets the account manager.
        /// </summary>
        /// <value>
        /// The account manager.
        /// </value>
        public AccountManager AccountManager { get; protected set; }

        /// <summary>
        /// Gets or sets the gift card manager.
        /// </summary>
        /// <value>
        /// The gift card manager.
        /// </value>
        public GiftCardManager GiftCardManager { get; protected set; }

        /// <summary>
        /// Gets or sets the store manager.
        /// </summary>
        /// <value>
        /// The store manager.
        /// </value>
        public StoreManager StoreManager { get; protected set; }

        /// <summary>
        /// Handles the index view of the controller
        /// </summary>
        /// <returns>The action for this view</returns>
        [HttpGet]
        public ActionResult StartCheckout()
        {
            if (Sitecore.Context.PageMode.IsPreview)
            {
                return View();
            }

            var viewRequested = this.Request.QueryString["view"];
            if (this.CurrentStorefront.UseAXCheckout || (viewRequested != null && viewRequested == "DynamicsCheckout"))
            {
                return View(this.GetRenderingView("DynamicsCheckout"));
            }

            var response = this.CartManager.GetCurrentCart(CurrentStorefront, CurrentVisitorContext, true);
            var cart = (CommerceCart)response.ServiceProviderResult.Cart;
            if (cart.Lines == null || !cart.Lines.Any())
            {
                var cartPageUrl = StorefrontManager.StorefrontUri("/shoppingcart");
                return Redirect(cartPageUrl);
            }

            AddSupportingDataToViewBag(cart, true);
            return View(this.CurrentRenderingView, new CartRenderingModel(response.Result));
        }

        /// <summary>
        /// Retrieves data required to start the checkout process.
        /// </summary>
        /// <returns>Data required to start the checkout process.</returns>
        [HttpGet]
        public JsonResult GetCheckoutData()
        {
            var result = new GetCheckoutDataJsonResult();

            var response = this.CartManager.GetCurrentCart(CurrentStorefront, CurrentVisitorContext, true);
            result.SetErrors(response.ServiceProviderResult);
            var cart = (CommerceCart)response.ServiceProviderResult.Cart;
            if (cart.Lines == null || !cart.Lines.Any())
            {
                return result;
            }

            result.ShowShipping = true;
            result.ShowPayment = false;
            result.IsCheckoutInfoValid = false;

            this.AddShippingOptionsToResult(result, cart);
            this.AddShippingMethodsToResult(result, cart);
            result.Countries = this.GetAvailableCountries();
            result.PaymentOptions = this.GetPaymentOptions(cart);
            result.PaymentMethods = this.GetPaymentMethods();

            // get current shipping info
            result.CurrentOrderShippingAddress = this.GetCurrentOrderShippingAddress(cart);
            result.ShippingMethods = new List<ShippingMethod>().AsReadOnly();

            // get current payment info
            result.GiftCardPayment = cart.Payment != null && cart.Payment.Any() ? cart.Payment.OfType<GiftCardPaymentInfo>().FirstOrDefault() : new GiftCardPaymentInfo { Amount = 0M };
            result.LoyaltyCardPayment = cart.Payment != null && cart.Payment.Any() ? cart.Payment.OfType<LoyaltyCardPaymentInfo>().FirstOrDefault() : new LoyaltyCardPaymentInfo { Amount = 0M };
            result.CreditCardPayment = cart.Payment != null && cart.Payment.Any() ? cart.Payment.OfType<CommerceCreditCardPaymentInfo>().FirstOrDefault() : new CommerceCreditCardPaymentInfo { Amount = 0M };
            result.CurrentBillingAddress = this.GetCurrentBillingAddress(cart);

            // get user's address if authenticated
            result.IsUserAuthenticated = Sitecore.Context.User.IsAuthenticated;
            if (Sitecore.Context.User.IsAuthenticated)
            {
                result.UserAddresses = this.GetUserAddresses();
            }

            result.UserEmail = Sitecore.Context.User.IsAuthenticated ? CurrentVisitorContext.ResolveCommerceUser(this.AccountManager).Email : string.Empty;
            result.CartLoyaltyCardNumber = cart.LoyaltyCardID;
            result.IsCheckoutInfoValid = true;

            return Json(result, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Submits the order in json.
        /// </summary>
        /// <param name="inputModel">The input model.</param>
        /// <returns></returns>
        [HttpPost]
        public JsonResult SubmitOrderJson(SubmitOrderInputModel inputModel)
        {
            Assert.ArgumentNotNull(inputModel, "inputModel");

            var response = this.OrderManager.SubmitVisitorOrder(CurrentStorefront, CurrentVisitorContext, inputModel);
            var result = new SubmitOrderJsonResult(response.ServiceProviderResult);
            if (response.ServiceProviderResult.Success)
            {
                if (response.ServiceProviderResult.CartWithErrors == null)
                {
                    result.ConfirmUrl = string.Concat(StorefrontManager.StorefrontUri("checkout/Order Confirmation"), "?confirmationId=", (response.Result.TrackingNumber));
                }
            }

            return Json(result, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Gets the available shipping methods.
        /// </summary>
        /// <param name="inputModel">The input model.</param>
        /// <returns>
        /// The available shipping methods.
        /// </returns>
        [HttpPost]
        public JsonResult GetShippingMethodsJson(GetShippingMethodsInputModel inputModel)
        {
            Assert.ArgumentNotNull(inputModel, "inputModel");
            Assert.ArgumentNotNull(inputModel.ShippingAddress, "inputModel.ShippingAddress");
            Assert.ArgumentNotNull(inputModel.ShippingPreferenceType, "inputModel.ShippingPreferenceType");

            var response = this.ShippingManager.GetShippingMethods(CurrentStorefront, CurrentVisitorContext, inputModel);
            var result = new GetShippingMethodsJsonResult(response.ServiceProviderResult);
            return Json(result, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Sets the shipping methods.
        /// </summary>
        /// <returns>
        /// The action for this view
        /// </returns>
        [HttpPost]
        public JsonResult SetShippingMethodsJson(SetShippingMethodsInputModel inputModel)
        {
            Assert.ArgumentNotNull(inputModel, "inputModel");

            var response = this.CartManager.SetShippingMethods(CurrentStorefront, CurrentVisitorContext, inputModel);
            var result = new CartJsonResult(response.ServiceProviderResult);
            if (response.ServiceProviderResult.Success) {
                result.Initialize(response.Result);
            }
            return Json(result, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Gets the nearby stores.
        /// </summary>
        /// <param name="inputModel">The input model.</param>
        /// <returns>
        /// A list of stores
        /// </returns>
        [HttpPost]
        public JsonResult GetNearbyStoresJson(GetNearbyStoresInputModel inputModel)
        {
            Assert.ArgumentNotNull(inputModel, "inputModel");

            var response = this.StoreManager.GetNearbyStores(CurrentStorefront, CurrentVisitorContext, inputModel);
            var result = new GetNearbyStoresJsonResult(response.ServiceProviderResult);
            return Json(result, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Gets the available states.
        /// </summary>
        /// <param name="countryCode">The country code.</param>
        /// <returns>
        /// A list of states based on the country
        /// </returns>
        [HttpPost]
        public JsonResult GetAvailableStatesJson(string countryCode)
        {
            Assert.ArgumentNotNullOrEmpty(countryCode, "countryCode");

            var response = this.OrderManager.GetAvailableStates(CurrentStorefront, CurrentVisitorContext, countryCode);
            var result = new GetAvailableStatesJsonResult(response.ServiceProviderResult);
            if (response.ServiceProviderResult.Success)
            {
                result.States = response.Result;
            }

            return Json(result, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Gets the gift card balance.
        /// </summary>
        /// <param name="giftCardId">The gift card identifier.</param>
        /// <returns>
        /// A response containing the gift card balance.
        /// </returns>
        [HttpPost]
        public JsonResult GetGiftCardBalanceJson(string giftCardId)
        {
            Assert.ArgumentNotNullOrEmpty(giftCardId, "giftCardId");

            var response = this.GiftCardManager.GetGiftCardBalance(CurrentStorefront, CurrentVisitorContext, giftCardId);
            var result = new GetGiftCardJsonResult(response.ServiceProviderResult);
            return Json(result, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Gets the gift card balance.
        /// </summary>
        /// <param name="inputModel">The input model.</param>
        /// <returns>
        /// A response containing the gift card balance.
        /// </returns>
        [HttpPost]
        public JsonResult CheckGiftCardBalance(GetGiftCardBalanceInputModel inputModel)
        {
            Assert.ArgumentNotNull(inputModel, "inputModel");
            Assert.ArgumentNotNullOrEmpty(inputModel.GiftCardId, "inputModel.GiftCardId");

            var response = this.GiftCardManager.GetGiftCardBalance(CurrentStorefront, CurrentVisitorContext, inputModel.GiftCardId);
            var result = new GetGiftCardJsonResult(response.ServiceProviderResult);
            return Json(result, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Applies the discount.
        /// </summary>
        /// <param name="promoCode">The action request.</param>
        /// <returns>
        /// A result containing the updated cart information.
        /// </returns>
        [HttpPost]
        public JsonResult ApplyDiscountJson(string promoCode)
        {
            Assert.ArgumentNotNull(promoCode, "promoCode");

            var response = this.CartManager.AddPromoCodeToCart(CurrentStorefront, CurrentVisitorContext, promoCode);
            var result = new CartJsonResult(response.ServiceProviderResult);
            if (response.ServiceProviderResult.Success)
            {
                result.Initialize(response.Result);
            }

            return Json(result, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Removes a discount.
        /// </summary>
        /// <param name="promoCode">The promo code.</param>
        /// <returns>
        /// A result containing the the updated cart information.
        /// </returns>
        [HttpPost]
        public ActionResult RemoveDiscountJson(string promoCode)
        {
            Assert.ArgumentNotNull(promoCode, "promoCode");

            var response = this.CartManager.RemovePromoCodeFromCart(CurrentStorefront, CurrentVisitorContext, promoCode);
            var result = new CartJsonResult(response.ServiceProviderResult);
            if (response.ServiceProviderResult.Success)
            {
                result.Initialize(response.Result);
            }

            return Json(result, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Deletes a line item from a cart
        /// </summary>
        /// <param name="externalCartLineId">The external cart line identifier.</param>
        /// <returns>
        /// A response containing the updated cart information
        /// </returns>
        [HttpPost]
        public JsonResult DeleteLineItemJson(string externalCartLineId)
        {
            Assert.ArgumentNotNullOrEmpty(externalCartLineId, "externalCartLineId");

            var response = this.CartManager.RemoveLineItemFromCart(CurrentStorefront, CurrentVisitorContext, externalCartLineId);
            var result = new CartJsonResult(response.ServiceProviderResult);
            if (response.ServiceProviderResult.Success)
            {
                result.Initialize(response.Result);
            }

            return Json(result, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Update a cart line item
        /// </summary>
        /// <param name="inputModel">The input model.</param>
        /// <returns>
        /// A result containing the updated cart information.
        /// </returns>
        [HttpPost]
        public JsonResult UpdateLineItemJson(UpdateCartLineInputModel inputModel)
        {
            Assert.ArgumentNotNull(inputModel, "inputModel");
            Assert.ArgumentNotNull(this.CartManager, "CartManager");
            Assert.ArgumentNotNullOrEmpty(inputModel.ExternalCartLineId, "inputModel.ExternalCartLineId");

            var response = this.CartManager.ChangeLineQuantity(CurrentStorefront, CurrentVisitorContext, inputModel);
            var result = new CartJsonResult(response.ServiceProviderResult);
            if (response.ServiceProviderResult.Success)
            {
                result.Initialize(response.Result);
            }

            return Json(result, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Updates the loytalty card.
        /// </summary>
        /// <param name="loyaltyCardNumber">The action request.</param>
        /// <returns>
        /// True is loyalty card was associated sucessfully, otherwise false
        /// </returns>
        [HttpPost]
        public JsonResult UpdateLoyaltyCard(string loyaltyCardNumber)
        {
            // dha: todo: remove after adapting to all-json version
            Assert.ArgumentNotNullOrEmpty(loyaltyCardNumber, "loyaltyCardNumber");

            var response = this.LoyaltyProgramManager.AssociateLoyaltyCardWithCurrentCart(CurrentStorefront, CurrentVisitorContext, loyaltyCardNumber);
            return Json(new { wasUpdated = response.Result, errors = response.ServiceProviderResult.SystemMessages.Select(sm => sm.Message).ToList() }, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Updates the loytalty card.
        /// </summary>
        /// <param name="loyaltyCardNumber">The loyalty card number.</param>
        /// <returns>
        /// A response indicating whether the loyalty card was successfully updated or not.
        /// </returns>
        [HttpPost]
        public JsonResult UpdateLoyaltyCardJson(string loyaltyCardNumber)
        {
            Assert.ArgumentNotNullOrEmpty(loyaltyCardNumber, "loyaltyCardNumber");

            var response = this.LoyaltyProgramManager.AssociateLoyaltyCardWithCurrentCart(CurrentStorefront, CurrentVisitorContext, loyaltyCardNumber);
            var result = new UpdateLoyaltyCardJsonResult(response.ServiceProviderResult);
            result.WasUpdated = response.Result;

            return Json(result, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Confirms the order submitted.
        /// </summary>
        /// <param name="confirmationId">The order identifier.</param>
        /// <returns>
        /// the submitted view
        /// </returns>
        public ActionResult Confirm(string confirmationId)
        {
            if (Sitecore.Context.PageMode.IsPreview)
            {
                return View("Submitted");
            }

            Assert.ArgumentNotNullOrEmpty(confirmationId, "confirmationId");
            var response = this.OrderManager.GetOrderDetails(CurrentStorefront, CurrentVisitorContext, confirmationId);
            return View("Submitted", response.Result);
        }

        /// <summary>
        /// Confirms the order submitted.
        /// </summary>
        /// <param name="confirmationId">The order identifier.</param>
        /// <returns>
        /// A result containing the order information.
        /// </returns>
        public JsonResult ConfirmJson(string confirmationId)
        {
            Assert.ArgumentNotNullOrEmpty(confirmationId, "confirmationId");

            if (Sitecore.Context.PageMode.IsPreview)
            {
                var emptyResult = new CartJsonResult();
                emptyResult.IsPreview = true;
                return Json(emptyResult, JsonRequestBehavior.AllowGet);
            }

            var response = this.OrderManager.GetOrderDetails(CurrentStorefront, CurrentVisitorContext, confirmationId);
            var result = new OrderJsonResult(response.ServiceProviderResult);
            result.Initialize(response.Result);

            return Json(result, JsonRequestBehavior.AllowGet);
        }

        private void AddSupportingDataToViewBag(CommerceCart cart, bool showShipping)
        {
            // dha: todo: remove after adapting to all-json version
            ViewBag.ShowShipping = showShipping;
            ViewBag.ShowPayment = !showShipping;
            ViewBag.IsCheckoutInfoValid = false;

            this.GetShippingOptions(cart);
            this.GetAllShippingMethods(cart);
            ViewBag.Countries = this.GetAvailableCountries();
            ViewBag.PaymentOptions = this.GetPaymentOptions(cart);
            ViewBag.PaymentMethods = this.GetPaymentMethods();

            // get current shipping info
            ViewBag.CurrentOrderShippingAddress = this.GetCurrentOrderShippingAddress(cart);
            ViewBag.ShippingMethods = new List<ShippingMethod>().AsReadOnly();

            // get current payment info
            ViewBag.GiftCardPayment = cart.Payment != null && cart.Payment.Any() ? cart.Payment.OfType<GiftCardPaymentInfo>().FirstOrDefault() : new GiftCardPaymentInfo { Amount = 0M };
            ViewBag.LoyaltyCardPayment = cart.Payment != null && cart.Payment.Any() ? cart.Payment.OfType<LoyaltyCardPaymentInfo>().FirstOrDefault() : new LoyaltyCardPaymentInfo { Amount = 0M };
            ViewBag.CreditCardPayment = cart.Payment != null && cart.Payment.Any() ? cart.Payment.OfType<CommerceCreditCardPaymentInfo>().FirstOrDefault() : new CommerceCreditCardPaymentInfo { Amount = 0M };
            ViewBag.CurrentBillingAddress = this.GetCurrentBillingAddress(cart);

            // get user's address if authenticated
            if (Sitecore.Context.User.IsAuthenticated)
            {
                ViewBag.UserAddresses = this.GetUserAddresses();
            }

            ViewBag.UserEmail = Sitecore.Context.User.IsAuthenticated ? CurrentVisitorContext.ResolveCommerceUser(this.AccountManager).Email : string.Empty;
            ViewBag.CartLoyaltyCardNumber = cart.LoyaltyCardID;
            ViewBag.IsCheckoutInfoValid = true;
        }

        private IDictionary<string, Sitecore.Commerce.Connect.DynamicsRetail.Entities.CommerceParty> GetUserAddresses()
        {
            var response = this.AccountManager.GetUserAddresses(this.CurrentStorefront, this.CurrentVisitorContext, Sitecore.Context.User.Name);

            return response.Result.ToDictionary(party => party.ExternalId);
        }

        private void GetShippingOptions(CommerceCart cart)
        {
            // dha: todo: remove after adapting to all-json version
            var shippingOptionsResult = this.ShippingManager.GetShippingPreferences(cart);
            var orderShippingOptions = new List<ShippingOption>();
            var lineShippingOptions = new List<LineShippingOption>();
            if (shippingOptionsResult.ServiceProviderResult.Success)
            {
                orderShippingOptions = shippingOptionsResult.ServiceProviderResult.ShippingOptions.ToList();
                lineShippingOptions = shippingOptionsResult.ServiceProviderResult.LineShippingPreferences.ToList();
            }

            ViewBag.OrderShippingOptions = orderShippingOptions;
            ViewBag.LineShippingOptions = lineShippingOptions;
        }

        private void AddShippingOptionsToResult(GetCheckoutDataJsonResult result, CommerceCart cart)
        {
            var shippingOptionsResult = this.ShippingManager.GetShippingPreferences(cart);
            var orderShippingOptions = new List<ShippingOption>();
            var lineShippingOptions = new List<LineShippingOption>();
            if (shippingOptionsResult.ServiceProviderResult.Success)
            {
                orderShippingOptions = shippingOptionsResult.ServiceProviderResult.ShippingOptions.ToList();
                lineShippingOptions = shippingOptionsResult.ServiceProviderResult.LineShippingPreferences.ToList();
            }

            result.OrderShippingOptions = orderShippingOptions;
            result.LineShippingOptions = lineShippingOptions;
        }

        private IDictionary<string, string> GetAvailableCountries()
        {
            var countries = this.OrderManager.GetAvailableCountries().Result;
            return countries;
        }

        private IEnumerable<PaymentOption> GetPaymentOptions(CommerceCart cart)
        {
            var response = this.PaymentManager.GetPaymentOptions(this.CurrentStorefront, this.CurrentVisitorContext, cart);
            return response.Result;
        }

        private IEnumerable<PaymentMethod> GetPaymentMethods()
        {
            var response = this.PaymentManager.GetPaymentMethods(this.CurrentStorefront, this.CurrentVisitorContext, new PaymentOption());
            return response.Result;
        }

        private CommerceParty GetCurrentOrderShippingAddress(CommerceCart cart)
        {
            // TODO should handle more than one shipping on the cart
            ViewBag.States = new Dictionary<string, string>();
            var party = new CommerceParty { Name = MCC.ShippingAddressName, ExternalId = "0" };
            if (cart.Shipping == null || !cart.Shipping.Any() || cart.Parties == null || !cart.Parties.Any())
            {
                return party;
            }

            // ALL LINES HAVE TO BE SHIP TOGETHER FOR AN ORDER SHIPPING
            var lineIds = cart.Lines.Select(l => l.ExternalCartLineId).ToList();
            var shipping = cart.Shipping.FirstOrDefault(s => !lineIds.Except(s.LineIDs).Any()) as CommerceShippingInfo;
            if (shipping == null)
            {
                return party;
            }

            party = cart.Parties.FirstOrDefault(p => p.ExternalId.Equals(shipping.PartyID, StringComparison.OrdinalIgnoreCase)) as CommerceParty;
            if (party == null)
            {
                return new CommerceParty { Name = MCC.ShippingAddressName, ExternalId = "0" };
            }

            if (!string.IsNullOrEmpty(party.Country))
            {
                var statesResponse = this.OrderManager.GetAvailableStates(this.CurrentStorefront, this.CurrentVisitorContext, party.CountryCode);
                ViewBag.States = statesResponse.ServiceProviderResult;
            }

            return party;
        }

        private CommerceParty GetCurrentBillingAddress(CommerceCart cart)
        {
            var party = new CommerceParty { Name = MCC.BillingAddressName, ExternalId = "1" };
            if (cart.Payment == null || !cart.Payment.Any() || cart.Parties == null || !cart.Parties.Any())
            {
                return party;
            }

            var payment = cart.Payment.FirstOrDefault();
            if (payment == null)
            {
                return party;
            }

            var billingPartyId = payment.PartyID;
            return cart.Parties.FirstOrDefault(p => p.ExternalId.Equals(billingPartyId, StringComparison.OrdinalIgnoreCase)) as CommerceParty;
        }

        private void GetAllShippingMethods(CommerceCart cart)
        {
            // dha: todo: remove after adapting to all-json version
            var shippingRequest = new GetShippingMethodsInputModel() { ShippingPreferenceType = ShippingOptionType.None.Name };
            var response = this.ShippingManager.GetShippingMethods(this.CurrentStorefront, this.CurrentVisitorContext, shippingRequest);

            if (response.ServiceProviderResult.Success)
            {
                foreach (var sm in response.Result)
                {
                    var isEmailMethod = sm.GetPropertyValue("IsEmailShippingMethod") != null && (bool)sm.GetPropertyValue("IsEmailShippingMethod");
                    var isShipToStoreMethod = sm.GetPropertyValue("IsShipToStoreShippingMethod") != null && (bool)sm.GetPropertyValue("IsShipToStoreShippingMethod");

                    if (isEmailMethod)
                    {
                        ViewBag.EmailDeliveryMethodId = sm.ExternalId;
                        ViewBag.EmailDeliveryMethodName = sm.Description;
                    }

                    if (isShipToStoreMethod)
                    {
                        ViewBag.ShipToStoreDeliveryMethodId = sm.ExternalId;
                        ViewBag.ShipToStoreDeliveryMethodName = sm.Description;
                    }
                }

                return;
            }

            ViewBag.EmailDeliveryMethodId = string.Empty;
            ViewBag.EmailDeliveryMethodName = string.Empty;
            ViewBag.ShipToStoreDeliveryMethodId = string.Empty;
            ViewBag.ShipToStoreDeliveryMethodName = string.Empty;
        }

        private void AddShippingMethodsToResult(GetCheckoutDataJsonResult result, CommerceCart cart)
        {
            var shippingRequest = new GetShippingMethodsInputModel() { ShippingPreferenceType = ShippingOptionType.None.Name };
            var response = this.ShippingManager.GetShippingMethods(this.CurrentStorefront, this.CurrentVisitorContext, shippingRequest);

            if (response.ServiceProviderResult.Success)
            {
                foreach (var sm in response.Result)
                {
                    var isEmailMethod = sm.GetPropertyValue("IsEmailShippingMethod") != null && (bool)sm.GetPropertyValue("IsEmailShippingMethod");
                    var isShipToStoreMethod = sm.GetPropertyValue("IsShipToStoreShippingMethod") != null && (bool)sm.GetPropertyValue("IsShipToStoreShippingMethod");

                    if (isEmailMethod)
                    {
                        result.EmailDeliveryMethodId = sm.ExternalId;
                        result.EmailDeliveryMethodName = sm.Description;
                    }

                    if (isShipToStoreMethod)
                    {
                        result.ShipToStoreDeliveryMethodId = sm.ExternalId;
                        result.ShipToStoreDeliveryMethodName = sm.Description;
                    }
                }

                return;
            }

            result.EmailDeliveryMethodId = string.Empty;
            result.EmailDeliveryMethodName = string.Empty;
            result.ShipToStoreDeliveryMethodId = string.Empty;
            result.ShipToStoreDeliveryMethodName = string.Empty;
        }
    }
}


text:
//
// Copyright (c) Microsoft.  All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

namespace Microsoft.Azure.Commands.ApiManagement.ServiceManagement.Commands
{
    using System;
    using System.Globalization;
    using System.IO;
    using System.Management.Automation;
    using System.Security.Cryptography.X509Certificates;
    using Microsoft.Azure.Commands.ApiManagement.ServiceManagement.Models;
    using Properties;

    [Cmdlet("Set", ResourceManager.Common.AzureRMConstants.AzureRMPrefix + "ApiManagementCertificate", DefaultParameterSetName = FromFile)]
    [OutputType(typeof(PsApiManagementCertificate))]
    public class SetAzureApiManagementCertificate : AzureApiManagementCmdletBase
    {
        private const string FromFile = "LoadFromFile";
        private const string Raw = "Raw";

        [Parameter(
            ValueFromPipelineByPropertyName = true,
            Mandatory = true,
            HelpMessage = "Instance of PsApiManagementContext. This parameter is required.")]
        [ValidateNotNullOrEmpty]
        public PsApiManagementContext Context { get; set; }

        [Parameter(
            ValueFromPipelineByPropertyName = true,
            Mandatory = true,
            HelpMessage = "Identifier of certificate. This parameter is required.")]
        [ValidateNotNullOrEmpty]
        public String CertificateId { get; set; }

        [Parameter(
            ParameterSetName = FromFile,
            ValueFromPipelineByPropertyName = true,
            Mandatory = true,
            HelpMessage = "Path to the certificate file in .pfx format to be created/uploaded. " +
                          "This parameter is required if -PfxBytes not specified.")]
        public String PfxFilePath { get; set; }

        [Parameter(
            ParameterSetName = Raw,
            ValueFromPipelineByPropertyName = true,
            Mandatory = true,
            HelpMessage = "Bytes of the certificate file in .pfx format to be created/uploaded. " +
                          "This parameter is required if -PfxFilePath not specified.")]
        public Byte[] PfxBytes { get; set; }

        [Parameter(
            ValueFromPipelineByPropertyName = true,
            Mandatory = true,
            HelpMessage = "Password for the certificate. This parameter is required.")]
        [ValidateNotNullOrEmpty]
        public String PfxPassword { get; set; }

        [Parameter(
            ValueFromPipelineByPropertyName = true,
            Mandatory = false,
            HelpMessage = "If specified then instance of " +
                          "Microsoft.Azure.Commands.ApiManagement.ServiceManagement.Models.PsApiManagementCertificate type " +
                          " representing the modified certificate.")]
        public SwitchParameter PassThru { get; set; }

        public override void ExecuteApiManagementCmdlet()
        {
            byte[] rawBytes;
            if (ParameterSetName.Equals(FromFile))
            {
                FileInfo localFile = new FileInfo(this.GetUnresolvedProviderPathFromPSPath(this.PfxFilePath));
                if (!localFile.Exists)
                {
                    throw new FileNotFoundException(string.Format(CultureInfo.CurrentCulture, Resources.SourceFileNotFound, this.PfxFilePath));
                }

                using (var certStream = File.OpenRead(localFile.FullName))
                {
                    rawBytes = new byte[certStream.Length];
                    certStream.Read(rawBytes, 0, rawBytes.Length);
                }
            }
            else if (ParameterSetName.Equals(Raw))
            {
                rawBytes = PfxBytes;
            }
            else
            {
                throw new InvalidOperationException(string.Format("Parameter set name '{0}' is not supported.", ParameterSetName));
            }

            // check for valid certificate file/bytes
            new X509Certificate2(rawBytes, PfxPassword);

            var certificate = Client.CertificateSet(Context, CertificateId, rawBytes, PfxPassword);
            if (PassThru)
            {
                WriteObject(certificate);
            }
        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
Set-StrictMode -version 2.0
$ErrorActionPreference="Stop"

# Import Arcade functions
. (Join-Path $PSScriptRoot "tools.ps1")

[string]$binariesDir = Join-Path $RepoRoot "Binaries"

# Handy function for executing a command in powershell and throwing if it
# fails.
#
# Use this when the full command is known at script authoring time and
# doesn't require any dynamic argument build up.  Example:
#
#   Exec-Block { & $msbuild Test.proj }
#
# Original sample came from: http://jameskovacs.com/2010/02/25/the-exec-problem/
function Exec-Block([scriptblock]$cmd) {
    & $cmd

    # Need to check both of these cases for errors as they represent different items
    # - $?: did the powershell script block throw an error
    # - $lastexitcode: did a windows command executed by the script block end in error
    if ((-not $?) -or ($lastexitcode -ne 0)) {
        throw "Command failed to execute: $cmd"
    }
}

# This will exec a process using the console and return it's exit code. This will not
# throw when the process fails.
function Exec-Process([string]$command, [string]$commandArgs) {
    $startInfo = New-Object System.Diagnostics.ProcessStartInfo
    $startInfo.FileName = $command
    $startInfo.Arguments = $commandArgs
    $startInfo.UseShellExecute = $false
    $startInfo.WorkingDirectory = Get-Location

    $process = New-Object System.Diagnostics.Process
    $process.StartInfo = $startInfo
    $process.Start() | Out-Null

    $finished = $false
    try {
        while (-not $process.WaitForExit(100)) {
            # Non-blocking loop done to allow ctr-c interrupts
        }

        $finished = $true
        $process.ExitCode
    }
    finally {
        # If we didn't finish then an error occured or the user hit ctrl-c.  Either
        # way kill the process
        if (-not $finished) {
            $process.Kill()
        }
    }
}

function Exec-CommandCore([string]$command, [string]$commandArgs, [switch]$useConsole = $true) {
    if ($useConsole) {
        $exitCode = Exec-Process $command $commandArgs
        if ($exitCode -ne 0) {
            throw "Command failed to execute with exit code $($exitCode): $command $commandArgs"
        }
        return
    }

    $startInfo = New-Object System.Diagnostics.ProcessStartInfo
    $startInfo.FileName = $command
    $startInfo.Arguments = $commandArgs

    $startInfo.UseShellExecute = $false
    $startInfo.WorkingDirectory = Get-Location
    $startInfo.RedirectStandardOutput = $true
    $startInfo.CreateNoWindow = $true

    $process = New-Object System.Diagnostics.Process
    $process.StartInfo = $startInfo
    $process.Start() | Out-Null

    $finished = $false
    try {
        # The OutputDataReceived event doesn't fire as events are sent by the
        # process in powershell.  Possibly due to subtlties of how Powershell
        # manages the thread pool that I'm not aware of.  Using blocking
        # reading here as an alternative which is fine since this blocks
        # on completion already.
        $out = $process.StandardOutput
        while (-not $out.EndOfStream) {
            $line = $out.ReadLine()
            Write-Output $line
        }

        while (-not $process.WaitForExit(100)) {
            # Non-blocking loop done to allow ctr-c interrupts
        }

        $finished = $true
        if ($process.ExitCode -ne 0) {
            throw "Command failed to execute with exit code $($process.ExitCode): $command $commandArgs"
        }
    }
    finally {
        # If we didn't finish then an error occured or the user hit ctrl-c.  Either
        # way kill the process
        if (-not $finished) {
            $process.Kill()
        }
    }
}

# Handy function for executing a windows command which needs to go through
# windows command line parsing.
#
# Use this when the command arguments are stored in a variable.  Particularly
# when the variable needs reparsing by the windows command line. Example:
#
#   $args = "/p:ManualBuild=true Test.proj"
#   Exec-Command $msbuild $args
#
function Exec-Command([string]$command, [string]$commandArgs) {
    Exec-CommandCore -command $command -commandArgs $commandargs -useConsole:$false
}

# Functions exactly like Exec-Command but lets the process re-use the current
# console. This means items like colored output will function correctly.
#
# In general this command should be used in place of
#   Exec-Command $msbuild $args | Out-Host
#
function Exec-Console([string]$command, [string]$commandArgs) {
    Exec-CommandCore -command $command -commandArgs $commandargs -useConsole:$true
}

# Handy function for executing a powershell script in a clean environment with
# arguments.  Prefer this over & sourcing a script as it will both use a clean
# environment and do proper error checking
function Exec-Script([string]$script, [string]$scriptArgs = "") {
    Exec-Command "powershell" "-noprofile -executionPolicy RemoteSigned -file `"$script`" $scriptArgs"
}

# Ensure the proper SDK in installed in our %PATH%. This is how MSBuild locates the
# SDK. Returns the location to the dotnet exe
function Ensure-DotnetSdk() {
  if (-not (Test-Path global:_dotNetExe)) {
    $global:_dotNetExe = Join-Path (InitializeDotNetCli -install:$true) "dotnet.exe"
  }

  return $global:_dotNetExe
}
# Ensure a basic tool used for building our Repo is installed and
# return the path to it.
function Ensure-BasicTool([string]$name, [string]$version = "") {
    if ($version -eq "") {
        $version = Get-PackageVersion $name
    }

    $p = Join-Path (Get-PackagesDir) "$($name)\$($version)"
    if (-not (Test-Path $p)) {
        $toolsetProject = Join-Path $RepoRoot "build\ToolsetPackages\RoslynToolset.csproj"
        Write-Host "Downloading $name"
        Restore-Project $toolsetProject
    }

    return $p
}

# Ensure that MSBuild is installed and return the path to the
# executable to use.
function Ensure-MSBuild([switch]$xcopy = $false) {
    $both = Get-MSBuildKindAndDir -xcopy:$xcopy
    $msbuildDir = $both[1]
    switch ($both[0]) {
        "xcopy" { break; }
        "vscmd" { break; }
        "vsinstall" { break; }
        default {
            throw "Unknown MSBuild installation type $($both[0])"
        }
    }

    return Join-Path $msbuildDir "msbuild.exe"
}

# Returns the msbuild exe path and directory as a single return. This makes it easy
# to do one line MSBuild configuration in scripts
#   $msbuild, $msbuildDir = Ensure-MSBuildAndDir
function Ensure-MSBuildAndDir([string]$msbuildDir) {
    if ($msbuildDir -eq "") {
        $msbuild = Ensure-MSBuild
        $msbuildDir = Split-Path -parent $msbuild
    }
    else {
        $msbuild = Join-Path $msbuildDir "msbuild.exe"
    }

    return $msbuild, $msbuildDir
}

function Create-Directory([string]$dir) {
    New-Item $dir -ItemType Directory -ErrorAction SilentlyContinue | Out-Null
}

function Get-VersionCore([string]$name, [string]$versionFile) {
    $name = $name.Replace(".", "")
    $name = $name.Replace("-", "")
    $nodeName = "$($name)Version"
    $x = [xml](Get-Content -raw $versionFile)
    $node = $x.SelectSingleNode("//Project/PropertyGroup/$nodeName")
    if ($node -ne $null) {
        return $node.InnerText
    }

    throw "Cannot find package $name in $versionFile"

}

# Return the version of the NuGet package as used in this repo
function Get-PackageVersion([string]$name) {
    return Get-VersionCore $name (Join-Path $RepoRoot "build\Targets\Packages.props")
}

# Return the version of the specified tool
function Get-ToolVersion([string]$name) {
    return Get-VersionCore $name (Join-Path $RepoRoot "build\Targets\Tools.props")
}

# Locate the directory where our NuGet packages will be deployed.  Needs to be kept in sync
# with the logic in Version.props
function Get-PackagesDir() {
    $d = $null
    if ($env:NUGET_PACKAGES -ne $null) {
        $d = $env:NUGET_PACKAGES
    }
    else {
        $d = Join-Path $env:UserProfile ".nuget\packages\"
    }

    Create-Directory $d
    return $d
}

# Locate the directory of a specific NuGet package which is restored via our main
# toolset values.
function Get-PackageDir([string]$name, [string]$version = "") {
    if ($version -eq "") {
        $version = Get-PackageVersion $name
    }

    $p = Get-PackagesDir
    $p = Join-Path $p $name.ToLowerInvariant()
    $p = Join-Path $p $version
    return $p
}

# The intent of this script is to locate and return the path to the MSBuild directory that
# we should use for bulid operations.  The preference order for MSBuild to use is as
# follows:
#
#   1. MSBuild from an active VS command prompt
#   2. MSBuild from a compatible VS installation
#   3. MSBuild from the xcopy toolset
#
# This function will return two values: the kind of MSBuild chosen and the MSBuild directory.
function Get-MSBuildKindAndDir([switch]$xcopy = $false) {

    if ($xcopy) {
        Write-Output "xcopy"
        Write-Output (Get-MSBuildDirXCopy)
        return
    }

    # MSBuild from an active VS command prompt. Use the MSBuild here so long as it's from a
    # compatible Visual Studio. If not though throw and error out. Given the number of
    # environment variable changes in a developer command prompt it's hard to make guarantees
    # about subbing in a new MSBuild instance
    if (${env:VSINSTALLDIR} -ne $null) {
        $command = (Get-Command msbuild -ErrorAction SilentlyContinue)
        if ((Test-SupportedVisualStudioVersion ${env:VSCMD_VER}) -and ($command -ne $null) ) {
            $p = Split-Path -parent $command.Path
            Write-Output "vscmd"
            Write-Output $p
            return
        }
        else {
            $vsMinimumVersion = Get-ToolVersion "vsMinimum"
            throw "Developer Command Prompt for VS $(${env:VSCMD_VER}) is not recent enough. Please upgrade to {$vsMinimumVersion} or build from a normal CMD window"
        }
    }

    # Look for a valid VS installation
    try {
        $p = Get-VisualStudioDir
        $p = Join-Path $p "MSBuild\15.0\Bin"
        Write-Output "vsinstall"
        Write-Output $p
        return
    }
    catch {
        # Failures are expected here when no VS installation is present on the
        # machine.
    }

    Write-Output "xcopy"
    Write-Output (Get-MSBuildDirXCopy)
    return
}

# Locate the xcopy version of MSBuild
function Get-MSBuildDirXCopy() {
    $p = Ensure-BasicTool "RoslynTools.MSBuild"
    $p = Join-Path $p "tools\MSBuild\15.0\Bin"
    return $p
}

function Get-MSBuildDir([switch]$xcopy = $false) {
    $both = Get-MSBuildKindAndDir -xcopy:$xcopy
    return $both[1]
}

# Dose this version of Visual Studio meet our minimum requirements for building.
function Test-SupportedVisualStudioVersion([string]$version) {
    # This regex allows us to strip off any pre-release info that gets attached
    # to the version string. VS uses NuGet style pre-release by suffing version
    # with -<pre-release info>
    if (-not ($version -match "^([\d.]+)(\+|-)?.*$")) {
        return $false
    }

    $vsMinimumVersion = Get-ToolVersion "vsMinimum"
    $V = New-Object System.Version $matches[1]
    $min = New-Object System.Version $vsMinimumVersion
    return $v -ge $min;
}

# Get the directory and instance ID of the first Visual Studio version which
# meets our minimal requirements for the Roslyn repo.
function Get-VisualStudioDirAndId() {
    $vswhere = Join-Path (Ensure-BasicTool "vswhere") "tools\vswhere.exe"
    $output = Exec-Command $vswhere "-prerelease -requires Microsoft.Component.MSBuild -format json" | Out-String
    $j = ConvertFrom-Json $output
    foreach ($obj in $j) {

        # Need to be using at least Visual Studio 15.2 in order to have the appropriate
        # set of SDK fixes. Parsing the installationName is the only place where this is
        # recorded in that form.
        $name = $obj.installationName
        if ($name -match "VisualStudio(Preview)?/(.*)") {
            if (Test-SupportedVisualStudioVersion $matches[2]) {
                Write-Output $obj.installationPath
                Write-Output $obj.instanceId
                return
            }
        }
        else {
            Write-Host "Unrecognized installationName format $name"
        }
    }

    throw "Could not find a suitable Visual Studio Version"
}

# Get the directory of the first Visual Studio which meets our minimal
# requirements for the Roslyn repo
function Get-VisualStudioDir() {
    $both = Get-VisualStudioDirAndId
    return $both[0]
}

# Clear out the NuGet package cache
function Clear-PackageCache() {
    $dotnet = Ensure-DotnetSdk
    Exec-Console $dotnet "nuget locals all --clear"
}

# Restore a single project
function Restore-Project([string]$projectFileName, [string]$logFilePath = "") {
    $projectFilePath = $projectFileName
    if (-not (Test-Path $projectFilePath)) {
        $projectFilePath = Join-Path $RepoRoot $projectFileName
    }

    $logArg = ""
    if ($logFilePath -ne "") {
        $logArg = " /bl:$logFilePath"
    }

    Exec-Console (Ensure-DotNetSdk) "restore --verbosity quiet $projectFilePath $logArg"
}

function Unzip-File([string]$zipFilePath, [string]$outputDir) {
    Add-Type -AssemblyName System.IO.Compression.FileSystem | Out-Null
    [System.IO.Compression.ZipFile]::ExtractToDirectory($zipFilePath, $outputDir)
}


text:
import Ember from 'ember';

export default Ember.Route.extend({
  setupController(controller, model) {
    controller.set('model', model.map((point) => {
      const {id, title, lat, lng} = point.getProperties('id', 'title', 'lat', 'lng');

      return {
        id: id,
        title: title,
        position: {
          lat: lat,
          lng: lng
        }
      };
    }));
  }
});


text:
<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * CakePHP AttributeComponent
 * @author William Alarcon
 */
class AttributeComponent extends Component {

	public $components = array('Attributes.Session');
	private $controller;
	public $Attribute;
	public $uses = array('AttributeType', 'Attribute', 'Entity');

	public function __construct(ComponentCollection $collection, $settings = array()) {

		$this->controller = $collection->getController();
		$this->controller->loadModel('Attributes.AttributeType');
	}

	/*
	 * Developer: William Alarcon
	 * Description: Función para ser llamada desde toda la aplicación con el fin de obtener el listado de los tipos de atributos
	 * Parameters: entity_alias es el alias de la entidad
	 */

	public function getTypes($entity_alias = null, $moment = 'create', $attributes = false) {
		if (!$attributes) {
			$this->controller->AttributeType->unbindModel(
				array('hasMany' => array('Attribute'))
			);
		}

		$conditions = array();
		$conditions['Entity.alias'] = $entity_alias;

		if (is_array($moment)) {
			foreach ($moment as $m) {

				$conditions['OR'][]['AttributeType.moment'] = $m;
			}
		} else {
			$conditions['AttributeType.moment'] = $moment;
		}

		$Typeattributes = $this->controller->AttributeType->find('all', array(
			'order' => array('ordering' => 'asc'),
			'fields' => array('AttributeType.*'),
			'conditions' => $conditions,
			'recursive' => 1
			)
		);
		return $Typeattributes;
	}

	/*
	 * Developer: William Alarcon
	 * Description: Función para validar los direntes tipos de atributos
	 *
	 */

	public function validate($validates = null, $request = null) {
		$this->controller->loadModel('Attributes.AttributeType');
		foreach ($validates as $validated) {
			$name = $validated['AttributeType']['id'];
			$rule = $validated['AttributeType']['regexp_validation'];
			if ($validated['AttributeType']['input_type'] == 4 && $rule = 'notempty') {
				$this->controller->AttributeType->validate[$name] = array(
					'rule' => array('multiple', array(
							'min' => 1,
							'message' => $validated['AttributeType']['message'],
					)),
				);
			} else {
				if ($rule == 'url') {
					if (!empty($this->controller->request->data['AttributeType'][$name])) {
						$this->controller->AttributeType->validate[$name] = array(
							'regexp' => array(
								'rule' => $rule,
								'message' => $validated['AttributeType']['message'],
							),
						);
					}
				} else {
					$this->controller->AttributeType->validate[$name] = array(
						'regexp' => array(
							'rule' => $rule,
							'message' => $validated['AttributeType']['message'],
						),
					);
				}
			}
		}
		$this->controller->AttributeType->set($request);

		if ($this->controller->AttributeType->validates()) {
			return true;
		} else {
			return false;
		}
	}

	/*
	 * Developer: William Alarcon
	 * Description: Guardar los atributos
	 * Parameters:Atributos es el reques action de la vista y parent_entityid es el id al que se le va asignar los atributos
	 *
	 */

	public function saveAll($attributes = array(), $parent_entityid = null) {
		$this->controller->loadModel('Attributes.Attribute');

		foreach ($attributes as $key => $value) {
			if (is_array($value)) {
				$value_input = '';
				foreach ($value as $field) {
					$value_input.=$field . ',';
				}
				$this->controller->Attribute->create(
					array(
						'parent_entityid' => $parent_entityid,
						'attribute_type_id' => $key,
						'value' => trim($value_input, ','),
					)
				);
				$this->controller->Attribute->save();
			} else {
				$this->controller->Attribute->create(
					array(
						'parent_entityid' => $parent_entityid,
						'attribute_type_id' => $key,
						'value' => $value,
					)
				);
				$this->controller->Attribute->save();
			}
		}
	}

	/*
	 * Developer: William Alarcon
	 * Description: Obtener los registros de atributos
	 * Parameters: id es el id del los atributos a traer, entity_alias es el alias de la entidad
	 *
	 */

	public function getSaved($id = null, $entity_alias = null, $moment = 'create') {

		$this->controller->loadModel('Attributes.Entity');

		$id_entity = $this->controller->Entity->find('first', array(
			'fields' => array('id'),
			'conditions' => array('Entity.alias' => $entity_alias),
			'recursive' => -1
			)
		);

		if (!empty($id_entity)) {
			$this->controller->AttributeType->bindModel(array('belongsTo' => array('Entity')));
			$attributes_register = $this->controller->AttributeType->Attribute->find('all', array(
				'fields' => 'Attribute.*',
				'conditions' => array(
					'Attribute.parent_entityid' => $id,
					'AttributeType.entity_id' => $id_entity['Entity']['id']
				),
				'recursive' => 1,
				)
			);

			$attributes = $this->getTypes($entity_alias, $moment, true);
			/* --- SET ATTRIBUTS ---- */
			$attr = array(
				'AttributeType' => array(),
				'Attribute' => array(),
			);
			foreach ($attributes as $attributes_type) {
				foreach ($attributes_register as $attribute) {
					if ($attributes_type['AttributeType']['input_type'] == 4) {
						$select_option = explode(',', $attribute['Attribute']['value']);
						foreach ($select_option as $key => $value) {
							$attr['AttributeType'][$attributes_type['AttributeType']['id']][] = $value;
						}
					} else {
						if ($attributes_type['AttributeType']['id'] == $attribute['Attribute']['attribute_type_id']) {
							if (!isset($attr['AttributeType'][$attributes_type['AttributeType']['id']])) {
								$attr['AttributeType'][$attributes_type['AttributeType']['id']] = $attribute['Attribute']['value'] . ', ';
							} else {
								$attr['AttributeType'][$attributes_type['AttributeType']['id']] .= $attribute['Attribute']['value'] . ', ';
							}
						}
					}
				}
				if (isset($attr['AttributeType'][$attributes_type['AttributeType']['id']]) && $attributes_type['AttributeType']['input_type'] != 4) {
					$attr['AttributeType'][$attributes_type['AttributeType']['id']] = trim($attr['AttributeType'][$attributes_type['AttributeType']['id']], ', ');
				}
			}

//			pr($attr);

			return $attr;
		} else {
			return 'Entity alias no found';
		}
	}

	/*
	 * Developer: William Alarcon
	 * Description: Guardar los atributos
	 * Parameters:Atributos es el reques action de la vista y parent_entityid es el id al que se le va asignar los atributos
	 *
	 */

	public function edit($attributes = array(), $parent_entityid = null, $entity_alias = null) {
		$this->controller->loadModel('Attributes.AttributeType');
		$this->controller->loadModel('Attributes.Attribute');
		$this->controller->loadModel('Attributes.Entity');

		$id_entity = $this->controller->Entity->find('first', array(
			'fields' => array('id'),
			'conditions' => array('Entity.alias' => $entity_alias),
			'recursive' => -2
			)
		);

		if (!empty($id_entity)) {

			foreach ($attributes as $key => $value) {

				$this->controller->Attribute->deleteAll(array(
					'Attribute.parent_entityid' => $parent_entityid,
					'Attribute.attribute_type_id' => $key
					)
				);

				$is_multiple = $this->controller->AttributeType->find('first', array(
					'recursive' => 0,
					'fields' => array('AttributeType.is_multiple'),
					'conditions' => array('AttributeType.id' => $key),
					));

				if ($is_multiple['AttributeType']['is_multiple']) {
					$this->controller->Attribute->create(
						array(
							'parent_entityid' => $parent_entityid,
							'attribute_type_id' => $key,
							'value' => $value,
						)
					);
					$this->controller->Attribute->save();
				} else {
					if (is_array($value)) {
						$value_input = '';
						foreach ($value as $field) {
							$value_input.=$field . ',';
						}
						$this->controller->Attribute->create(
							array(
								'parent_entityid' => $parent_entityid,
								'attribute_type_id' => $key,
								'value' => trim($value_input, ','),
							)
						);
						$this->controller->Attribute->save();
					} else {
						$this->controller->Attribute->create(
							array(
								'parent_entityid' => $parent_entityid,
								'attribute_type_id' => $key,
								'value' => $value,
							)
						);
						$this->controller->Attribute->save();
					}
				}
			}
		} else {
			return 'Entity alias no found';
		}
	}

	public function setAttributes($parent_entityid = null, $entity_alias = null, $fields = array()) {
		$this->controller->loadModel('ViewAttribute');
		return $this->controller->ViewAttribute->find('all', array(
				'order' => array('ordering' => 'desc'),
				'fields' => $fields,
				'contidions' => array('parent_entityid' => $parent_entityid, 'entity_alias' => $entity_alias)
				)
		);
	}

}


text:
//The MIT License(MIT)

//Copyright(c) 2016 Alberto Rodriguez & LiveCharts Contributors

//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:

//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.

//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.

using LiveCharts.Defaults;
using LiveCharts.Definitions.Points;
using LiveCharts.Definitions.Series;
using LiveCharts.Dtos;

namespace LiveCharts.SeriesAlgorithms
{
    /// <summary>
    ///
    /// </summary>
    /// <seealso cref="LiveCharts.SeriesAlgorithm" />
    /// <seealso cref="LiveCharts.Definitions.Series.ICartesianSeries" />
    public class OhlcAlgorithm : SeriesAlgorithm, ICartesianSeries
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="OhlcAlgorithm"/> class.
        /// </summary>
        /// <param name="view">The view.</param>
        public OhlcAlgorithm(ISeriesView view) : base(view)
        {
            SeriesOrientation = SeriesOrientation.Horizontal;
            PreferredSelectionMode = TooltipSelectionMode.SharedXValues;
        }

        /// <summary>
        /// Updates this instance.
        /// </summary>
        public override void Update()
        {
            var castedSeries = (IFinancialSeriesView) View;

            const double padding = 1.2;

            var totalSpace = ChartFunctions.GetUnitWidth(AxisOrientation.X, Chart, View.ScalesXAt) - padding;

            double exceed = 0;
            double candleWidth = 0;

            if (totalSpace > castedSeries.MaxColumnWidth)
            {
                exceed = totalSpace - castedSeries.MaxColumnWidth;
                candleWidth = castedSeries.MaxColumnWidth;
            }
            else
            {
                candleWidth = totalSpace;
            }

            foreach (var chartPoint in View.ActualValues.GetPoints(View))
            {
                var x = ChartFunctions.ToDrawMargin(chartPoint.X, AxisOrientation.X, Chart, View.ScalesXAt);

                chartPoint.View = View.GetPointView(chartPoint,
                    View.DataLabels ? View.GetLabelPointFormatter()(chartPoint) : null);

                chartPoint.SeriesView = View;

                var ohclView = (IOhlcPointView) chartPoint.View;

                ohclView.Open = ChartFunctions.ToDrawMargin(chartPoint.Open, AxisOrientation.Y, Chart, View.ScalesYAt);
                ohclView.Close = ChartFunctions.ToDrawMargin(chartPoint.Close, AxisOrientation.Y, Chart, View.ScalesYAt);
                ohclView.High = ChartFunctions.ToDrawMargin(chartPoint.High, AxisOrientation.Y, Chart, View.ScalesYAt);
                ohclView.Low = ChartFunctions.ToDrawMargin(chartPoint.Low, AxisOrientation.Y, Chart, View.ScalesYAt);

                ohclView.Width = candleWidth - padding > 0 ? candleWidth - padding : 0;
                ohclView.Left = x + exceed/2 + padding;
                ohclView.StartReference = (ohclView.High + ohclView.Low)/2;

                chartPoint.ChartLocation = new CorePoint(x + exceed/2, (ohclView.High + ohclView.Low)/2);

                chartPoint.View.DrawOrMove(null, chartPoint, 0, Chart);
            }
        }

        double ICartesianSeries.GetMinX(AxisCore axis)
        {
            return AxisLimits.StretchMin(axis);
        }

        double ICartesianSeries.GetMaxX(AxisCore axis)
        {
            return AxisLimits.UnitRight(axis);
        }

        double ICartesianSeries.GetMinY(AxisCore axis)
        {
            return AxisLimits.SeparatorMin(axis);
        }

        double ICartesianSeries.GetMaxY(AxisCore axis)
        {
            return AxisLimits.SeparatorMaxRounded(axis);
        }
    }
}


text:
var Ajax = {}

Ajax.sendRequest = function(url, callback, postData, file) {

	//set file to false if it is not already set.  If it is set then
    //it is supposed to be true.  If it is set to true that indicates that a file is
    //being sent.
    if (file === undefined){
        file = false;
    }

    //creates the XML object
    var req = Ajax.createXMLHttpObject();

	//if returns false cancel operation
	if (!req){return};

	//check to see if postData was passed if so set method to POST
	var method = (postData) ? "POST" : "GET";

	//call the open method, send the method "POST" or "GET" and pass true
	req.open(method,url,true);

	//if postData is sent and the file is zero meaning we are not sending a file then set request header for forms, otherwise JavaScript will decide the header type on the req.send method.
	if (postData && !file){
		req.setRequestHeader('Content-type','application/x-www-form-urlencoded');
    }
	//if everything returns ok send req value to "callback"
	req.onreadystatechange = function () {
		if (req.readyState !== 4) return;
		if (req.status !== 200 && req.status !== 304) {
			return;
		}
		callback(req);
	}
	// if we have already completed the request, stop the function so as not
  	// to send it again
	if (req.readyState === 4){return;}

	//if postdata was included send it to server side page. Information
	//can be received by using $_POST['data'] (this is via PHP)

    //sending a file and some text
    if (postData && file){
		req.send(postData);
	}
    //sending text only
    else if (postData && !file){
        req.send("data="+postData);
    }
	else{
		req.send(null);
	}

}

//depending on the browser return appropriate request.
Ajax.XMLHttpFactories = [
	function () {return new XMLHttpRequest()},
	function () {return new ActiveXObject("Msxml2.XMLHTTP")},
	function () {return new ActiveXObject("Msxml3.XMLHTTP")},
	function () {return new ActiveXObject("Microsoft.XMLHTTP")}
];

//This method cycles through all requests in XMLHttpFactories until
//one is found.
Ajax.createXMLHttpObject = function() {
	var xmlhttp = false;
	for (var i=0;i<Ajax.XMLHttpFactories.length;i++) {
		try {
			xmlhttp = Ajax.XMLHttpFactories[i]();
		}
		catch (e) {
			continue;
		}
		break;
	}
	return xmlhttp;
}


text:
static void Socket_New(var self, var args) {
    struct Socket* socket = self;
    socket->sin  = get(args, $I(0)) ? c_int(get(args, $I(0))) : 0;
    socket->sout = get(args, $I(1)) ? c_int(get(args, $I(1))) : 1;
    socket->serr = get(args, $I(2)) ? c_int(get(args, $I(2))) : 2;
}

static int Socket_Show(var self, var output, int pos) {
    struct Socket* socket = self;
    return print_to(output, pos,
        "[ %d === %d ===> %d ]",
        $I(socket -> sout), $I(socket -> serr), $I(socket -> sin));
}

var Socket = Cello(Socket,
    Instance(New, Socket_New, NULL),
    Instance(Show, Socket_Show, NULL));

var read_message()
{
    char buffer[LINEBUFSIZE];
    ssize_t recv_result;
    int offset = 0;
    while (1) {
        ssize_t recv_result = recv(0, buffer + offset, LINEBUFSIZE, 0);
        if (recv_result < 0) {
            perror("recv error");
            return $S("");
        } else {
            // null terminate the buffer first
            buffer[offset + recv_result] = 0;

            if (buffer[offset + recv_result - 1] == '\n') { // newline, end of command
                buffer[offset + recv_result - 1] = 0;
                if (buffer[offset + recv_result - 2]  == '\r') buffer[offset + recv_result - 2] = 0;
                return $S(buffer);
            } else {
                offset += recv_result;
            }
        }
    }
}

// void send_message(struct Socket* socket, var message_)
void send_message(var message_)
{
    struct String* message = cast(message_, String);
    int send_result = send(1, c_str(message), len(message), 0);
    // int send_result = send(socket->sout, c_str(message), len(message), 0);
    if (send_result < 0) {
        perror("sending message");
    }
}

void create_server(struct Int* port_number, struct Function* child_process)
{
    var err = $(File, fdopen(dup(2), "w"));

    struct sockaddr_in server_address;
    struct sockaddr_in client_address;

    // initialize server address
    bzero((char *) &server_address, sizeof(server_address));
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = INADDR_ANY;
    server_address.sin_port = htons(c_int(port_number));

    // opening socket
    int socket_fd = socket(PF_INET, SOCK_STREAM, 0);
    if (socket_fd < 0) {
        perror("opening stream socket");
    }

    // configure socket to SO_REUSEADDR
    int true_ = 1;
    setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &true_, sizeof(int));

    // binding socket
    int bind_result = bind(socket_fd, (struct sockaddr *) &server_address, sizeof(server_address));
    if (bind_result < 0) {
        perror("binding socket");
    }

    // listening socket
    int listen_result = listen(socket_fd, 0);
    if (listen_result < 0) {
        perror("listening socket");
    }

    // non-stop accepting
    while (1) {
        socklen_t client_length = sizeof(client_address);
        int client_socket_fd_in = accept(socket_fd, (struct sockaddr *) &client_address, &client_length);
        int client_socket_fd_out = dup(client_socket_fd_in);
        int client_socket_fd_err = dup(client_socket_fd_in);
        if (client_socket_fd_in < 0) {
            perror("accepting socket");
        }
        if (client_socket_fd_out < 0) {
            perror("duping socket");
        }

        // forking child processes
        pid_t child_pid = fork();
        if (child_pid < 0) {
            perror("fork error");
        } else if (child_pid == 0) {    //  child process
            close(socket_fd);
            call(child_process,
                $(Socket, client_socket_fd_in, client_socket_fd_out, client_socket_fd_err),
                err // custom stderr
            );
            exit(EXIT_SUCCESS);
        } else {                        //  parent process
            close(client_socket_fd_in);
            close(client_socket_fd_out);
            close(client_socket_fd_err);
        }
    }

    close(socket_fd);
}

var replace_socket(struct Socket* socket)
{
    // replace STDIN 0
    if (socket->sin != 0) {
        // print_to($(File, stderr), 0, "==> %$\n", $I(socket->sin));
        close(0);
        if (dup(socket->sin) < 0)
            fprintf(stderr, "%s %d: %s\n", "replace dup stdin", socket->sin , strerror(errno));
        close(socket->sin);
    }

    // replace STDOUT 1
    if (socket->sout != 1) {
        // print_to($(File, stderr), 0, "%$ ==>\n", $I(socket->sout));
        close(1);
        if (dup(socket->sout) < 0) {
            fprintf(stderr, "%s %d: %s\n", "replace dup stdout", socket->sout , strerror(errno));
        }
        close(socket->sout);
    }

    // replace STDERR 2
    if (socket->serr != 2) {
        // print_to($(File, stderr), 0, "== %$ ==>\n", $I(socket->serr));
        close(2);
        if (dup(socket->serr) < 0)
            fprintf(stderr, "%s %d: %s\n", "replace dup stderr", socket->serr , strerror(errno));
        close(socket->serr);
    }
    return NULL;
}

void close_socket(struct Socket* socket)
{
    // close socket IN
    if (socket->sin != 0) {
        // print_to($(File, stderr), 0, "=/=> %$\n", $I(socket->sin));
        close(socket->sin);
    }

    // close socket OUT
    if (socket->sout != 1) {
        // print_to($(File, stderr), 0, "%$ =/=>\n", $I(socket->sout));
        close(socket->sout);
    }

    // close socket ERR
    if (socket->serr != 2) {
        // print_to($(File, stderr), 0, "=/ %$ /=>\n", $I(socket->serr));
        close(socket->serr);
    }
}

var create_pipe()
{
    int fds[2];
    if (pipe(fds) == -1) {
        perror("pipe");
        return NULL;
    } else {
        // print_to($(File, stderr), 0, "creating %$\n", $(Socket, fds[0], fds[1], 2));
        return new(Socket, $I(fds[0]), $I(fds[1]), $I(2));
    }
}


text:
typedef struct {
    __unsafe_unretained ALAssetRepresentation *representation;
    __unsafe_unretained NSError *error;
} ProviderCreationInfo;

typedef enum {
    AssetTypeUnknown,
    AssetTypePhoto,
    AssetTypeVideo
} AssetType;

@implementation TSSourceALAsset {
    ALAsset *asset;
    AssetType type;
}

- (id)initWithAsset:(ALAsset *)_asset
{
    self = [super init];
    if (self) {
        NSParameterAssert(_asset);
        asset = _asset;
        [self setupAssetType];
    }
    return self;
}

- (void)setupAssetType
{
    NSString *assetTypeString = [asset valueForProperty:ALAssetPropertyType];
    if ([assetTypeString isEqualToString:ALAssetTypePhoto]) {
        type = AssetTypePhoto;
    } else if ([assetTypeString isEqualToString:ALAssetTypeVideo]) {
        type = AssetTypeVideo;
    } else {
        type = AssetTypeUnknown;
    }
}

- (BOOL)isPhoto
{
    return type == AssetTypePhoto;
}

- (BOOL)isVideo
{
    return type == AssetTypeVideo;
}

- (double)videoDuration
{
    double result = 0;
    if ([self isVideo]) {
        result = [[asset valueForProperty:ALAssetPropertyDuration] doubleValue];
    }
    return result;
}

- (NSString *)identifier
{
    return [super identifier] ? [super identifier] : asset.identifier;
}

- (UIImage *)placeholder
{
    CGImageRef placeholder = [asset aspectRatioThumbnail];;
    return [UIImage imageWithCGImage:placeholder];
}

- (UIImage *)thumbnailWithSize:(CGSize)size isCancelled:(const BOOL *)isCancelled error:(NSError *__autoreleasing *)error
{
    UIImage *result = nil;
    @autoreleasepool {
        if ([self isPhoto]) {
            result = [self imageThumbnailWithSize:size isCancelled:isCancelled error:error];
        } else if ([self isVideo]) {
            result = [self videoThumbnailWithSize:size isCancelled:isCancelled error:error];
        } else {
            if (error) {
                *error = [NSError errorWithDomain:@"TSSourceALAsset" code:0 userInfo:@{NSLocalizedDescriptionKey : @"Unknown type of ALAsset"}];
            }
        }
    }
    return result;
}

- (UIImage *)videoThumbnailWithSize:(CGSize)size isCancelled:(const BOOL *)isCancelled error:(NSError *__autoreleasing *)error
{
    ALAssetRepresentation *representation = [asset defaultRepresentation];
    NSURL *videoURL = [representation url];

    TSSourceVideo *videoSource = [[TSSourceVideo alloc] initWithVideoURL:videoURL thumbnailSecond:0];

    return [videoSource thumbnailWithSize:size isCancelled:isCancelled error:error];
}

- (UIImage *)imageThumbnailWithSize:(CGSize)size isCancelled:(const BOOL *)isCancelled error:(NSError *__autoreleasing *)error
{
    NSUInteger thumbSize = (NSUInteger)fmaxf(size.width, size.height);
    ALAssetRepresentation *representation = [asset defaultRepresentation];

    CGDataProviderDirectCallbacks callbacks = {
            .version = 0,
            .getBytePointer = NULL,
            .releaseBytePointer = NULL,
            .getBytesAtPosition = GetBytesCallback,
            .releaseInfo = ReleaseInfoCallback,
    };

    ProviderCreationInfo *info = malloc(sizeof(ProviderCreationInfo));
    info->representation = Retain(representation);
    info->error = nil;

    CGDataProviderRef provider = CGDataProviderCreateDirect((void *)info, [representation size], &callbacks);

    NSError *providerError = info->error;

    CGImageSourceRef source;
    @autoreleasepool {
        source = CGImageSourceCreateWithDataProvider(provider, NULL);
    }

    if (providerError || *isCancelled) {
        if (error) {
            *error = providerError;
        }
        CFRelease(source);
        CFRelease(provider);
        return nil;
    }

    NSDictionary *options = @{(NSString *)kCGImageSourceCreateThumbnailFromImageAlways : @YES,
            (NSString *)kCGImageSourceThumbnailMaxPixelSize : @(thumbSize),
            (NSString *)kCGImageSourceCreateThumbnailWithTransform : @YES
    };

    CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(source, 0, (__bridge CFDictionaryRef)options);
    CFRelease(source);
    CFRelease(provider);

    if (!imageRef) {
        if (error) {
            *error = [NSError errorWithDomain:@"TSSourceALAsset" code:0 userInfo:@{NSLocalizedDescriptionKey : @"Can't create thumbnail by CGImageSourceCreateThumbnailAtIndex. Unknown error."}];
        }
        return nil;
    }

    UIImage *toReturn = [UIImage imageWithCGImage:imageRef];

    CFRelease(imageRef);

    return toReturn;
}

static size_t GetBytesCallback(void *info, void *buffer, off_t position, size_t count)
{
    ProviderCreationInfo *providerInfo = (ProviderCreationInfo *)info;
    size_t countRead;

    ALAssetRepresentation *rep = providerInfo->representation;

    NSError *error = nil;
    countRead = [rep getBytes:(uint8_t *)buffer fromOffset:position length:count error:&error];

    if (countRead == 0 && error) {
        providerInfo->error = error;
    }
    return countRead;
}

static void ReleaseInfoCallback(void *info)
{
    ProviderCreationInfo *providerInfo = (ProviderCreationInfo *)info;
    Release(providerInfo->representation);
    free(providerInfo);
}

@end