text:
package api4

import (
	"net/http"

	l4g "github.com/alecthomas/log4go"
	"github.com/mattermost/platform/app"
	"github.com/mattermost/platform/model"
	"github.com/mattermost/platform/utils"
)

func InitChannel() {
	l4g.Debug(utils.T("api.channel.init.debug"))

	BaseRoutes.Channels.Handle("", ApiSessionRequired(createChannel)).Methods("POST")
	BaseRoutes.Channels.Handle("/direct", ApiSessionRequired(createDirectChannel)).Methods("POST")
	BaseRoutes.Channels.Handle("/group", ApiSessionRequired(createGroupChannel)).Methods("POST")
	BaseRoutes.Channels.Handle("/members/{user_id:[A-Za-z0-9]+}/view", ApiSessionRequired(viewChannel)).Methods("POST")

	BaseRoutes.ChannelsForTeam.Handle("", ApiSessionRequired(getPublicChannelsForTeam)).Methods("GET")
	BaseRoutes.ChannelsForTeam.Handle("/deleted", ApiSessionRequired(getDeletedChannelsForTeam)).Methods("GET")
	BaseRoutes.ChannelsForTeam.Handle("/ids", ApiSessionRequired(getPublicChannelsByIdsForTeam)).Methods("POST")
	BaseRoutes.ChannelsForTeam.Handle("/search", ApiSessionRequired(searchChannelsForTeam)).Methods("POST")
	BaseRoutes.User.Handle("/teams/{team_id:[A-Za-z0-9]+}/channels", ApiSessionRequired(getChannelsForTeamForUser)).Methods("GET")

	BaseRoutes.Channel.Handle("", ApiSessionRequired(getChannel)).Methods("GET")
	BaseRoutes.Channel.Handle("", ApiSessionRequired(updateChannel)).Methods("PUT")
	BaseRoutes.Channel.Handle("/patch", ApiSessionRequired(patchChannel)).Methods("PUT")
	BaseRoutes.Channel.Handle("/restore", ApiSessionRequired(restoreChannel)).Methods("POST")
	BaseRoutes.Channel.Handle("", ApiSessionRequired(deleteChannel)).Methods("DELETE")
	BaseRoutes.Channel.Handle("/stats", ApiSessionRequired(getChannelStats)).Methods("GET")
	BaseRoutes.Channel.Handle("/pinned", ApiSessionRequired(getPinnedPosts)).Methods("GET")

	BaseRoutes.ChannelForUser.Handle("/unread", ApiSessionRequired(getChannelUnread)).Methods("GET")

	BaseRoutes.ChannelByName.Handle("", ApiSessionRequired(getChannelByName)).Methods("GET")
	BaseRoutes.ChannelByNameForTeamName.Handle("", ApiSessionRequired(getChannelByNameForTeamName)).Methods("GET")

	BaseRoutes.ChannelMembers.Handle("", ApiSessionRequired(getChannelMembers)).Methods("GET")
	BaseRoutes.ChannelMembers.Handle("/ids", ApiSessionRequired(getChannelMembersByIds)).Methods("POST")
	BaseRoutes.ChannelMembers.Handle("", ApiSessionRequired(addChannelMember)).Methods("POST")
	BaseRoutes.ChannelMembersForUser.Handle("", ApiSessionRequired(getChannelMembersForUser)).Methods("GET")
	BaseRoutes.ChannelMember.Handle("", ApiSessionRequired(getChannelMember)).Methods("GET")
	BaseRoutes.ChannelMember.Handle("", ApiSessionRequired(removeChannelMember)).Methods("DELETE")
	BaseRoutes.ChannelMember.Handle("/roles", ApiSessionRequired(updateChannelMemberRoles)).Methods("PUT")
	BaseRoutes.ChannelMember.Handle("/notify_props", ApiSessionRequired(updateChannelMemberNotifyProps)).Methods("PUT")
}

func createChannel(c *Context, w http.ResponseWriter, r *http.Request) {
	channel := model.ChannelFromJson(r.Body)
	if channel == nil {
		c.SetInvalidParam("channel")
		return
	}

	if channel.Type == model.CHANNEL_OPEN && !app.SessionHasPermissionToTeam(c.Session, channel.TeamId, model.PERMISSION_CREATE_PUBLIC_CHANNEL) {
		c.SetPermissionError(model.PERMISSION_CREATE_PUBLIC_CHANNEL)
		return
	}

	if channel.Type == model.CHANNEL_PRIVATE && !app.SessionHasPermissionToTeam(c.Session, channel.TeamId, model.PERMISSION_CREATE_PRIVATE_CHANNEL) {
		c.SetPermissionError(model.PERMISSION_CREATE_PRIVATE_CHANNEL)
		return
	}

	if sc, err := app.CreateChannelWithUser(channel, c.Session.UserId); err != nil {
		c.Err = err
		return
	} else {
		c.LogAudit("name=" + channel.Name)
		w.WriteHeader(http.StatusCreated)
		w.Write([]byte(sc.ToJson()))
	}
}

func updateChannel(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId()
	if c.Err != nil {
		return
	}

	channel := model.ChannelFromJson(r.Body)

	if channel == nil {
		c.SetInvalidParam("channel")
		return
	}

	var oldChannel *model.Channel
	var err *model.AppError
	if oldChannel, err = app.GetChannel(channel.Id); err != nil {
		c.Err = err
		return
	}

	if _, err = app.GetChannelMember(channel.Id, c.Session.UserId); err != nil {
		c.Err = err
		return
	}

	if !CanManageChannel(c, channel) {
		return
	}

	if oldChannel.DeleteAt > 0 {
		c.Err = model.NewLocAppError("updateChannel", "api.channel.update_channel.deleted.app_error", nil, "")
		c.Err.StatusCode = http.StatusBadRequest
		return
	}

	if oldChannel.Name == model.DEFAULT_CHANNEL {
		if (len(channel.Name) > 0 && channel.Name != oldChannel.Name) || (len(channel.Type) > 0 && channel.Type != oldChannel.Type) {
			c.Err = model.NewLocAppError("updateChannel", "api.channel.update_channel.tried.app_error", map[string]interface{}{"Channel": model.DEFAULT_CHANNEL}, "")
			c.Err.StatusCode = http.StatusBadRequest
			return
		}
	}

	oldChannel.Header = channel.Header
	oldChannel.Purpose = channel.Purpose

	oldChannelDisplayName := oldChannel.DisplayName

	if len(channel.DisplayName) > 0 {
		oldChannel.DisplayName = channel.DisplayName
	}

	if len(channel.Name) > 0 {
		oldChannel.Name = channel.Name
	}

	if len(channel.Type) > 0 {
		oldChannel.Type = channel.Type
	}

	if _, err := app.UpdateChannel(oldChannel); err != nil {
		c.Err = err
		return
	} else {
		if oldChannelDisplayName != channel.DisplayName {
			if err := app.PostUpdateChannelDisplayNameMessage(c.Session.UserId, channel.Id, c.Params.TeamId, oldChannelDisplayName, channel.DisplayName); err != nil {
				l4g.Error(err.Error())
			}
		}
		c.LogAudit("name=" + channel.Name)
		w.Write([]byte(oldChannel.ToJson()))
	}
}

func patchChannel(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId()
	if c.Err != nil {
		return
	}

	patch := model.ChannelPatchFromJson(r.Body)
	if patch == nil {
		c.SetInvalidParam("channel")
		return
	}

	oldChannel, err := app.GetChannel(c.Params.ChannelId)
	if err != nil {
		c.Err = err
		return
	}

	if !CanManageChannel(c, oldChannel) {
		return
	}

	if rchannel, err := app.PatchChannel(oldChannel, patch, c.Session.UserId); err != nil {
		c.Err = err
		return
	} else {
		c.LogAudit("")
		w.Write([]byte(rchannel.ToJson()))
	}
}

func restoreChannel(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId()
	if c.Err != nil {
		return
	}

	var channel *model.Channel
	var err *model.AppError
	if channel, err = app.GetChannel(c.Params.ChannelId); err != nil {
		c.Err = err
		return
	}
	teamId := channel.TeamId

	if !app.SessionHasPermissionToTeam(c.Session, teamId, model.PERMISSION_MANAGE_TEAM) {
		c.SetPermissionError(model.PERMISSION_MANAGE_TEAM)
		return
	}

	channel, err = app.RestoreChannel(channel)
	if err != nil {
		c.Err = err
		return
	}

	c.LogAudit("name=" + channel.Name)
	w.Write([]byte(channel.ToJson()))

}

func CanManageChannel(c *Context, channel *model.Channel) bool {
	if channel.Type == model.CHANNEL_OPEN && !app.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES) {
		c.SetPermissionError(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES)
		return false
	}

	if channel.Type == model.CHANNEL_PRIVATE && !app.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES) {
		c.SetPermissionError(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES)
		return false
	}

	return true
}

func createDirectChannel(c *Context, w http.ResponseWriter, r *http.Request) {
	userIds := model.ArrayFromJson(r.Body)
	allowed := false

	if len(userIds) != 2 {
		c.SetInvalidParam("user_ids")
		return
	}

	for _, id := range userIds {
		if len(id) != 26 {
			c.SetInvalidParam("user_id")
			return
		}
		if id == c.Session.UserId {
			allowed = true
		}
	}

	if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_CREATE_DIRECT_CHANNEL) {
		c.SetPermissionError(model.PERMISSION_CREATE_DIRECT_CHANNEL)
		return
	}

	if !allowed && !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
		c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
		return
	}

	if sc, err := app.CreateDirectChannel(userIds[0], userIds[1]); err != nil {
		c.Err = err
		return
	} else {
		w.WriteHeader(http.StatusCreated)
		w.Write([]byte(sc.ToJson()))
	}
}

func createGroupChannel(c *Context, w http.ResponseWriter, r *http.Request) {
	userIds := model.ArrayFromJson(r.Body)

	if len(userIds) == 0 {
		c.SetInvalidParam("user_ids")
		return
	}

	found := false
	for _, id := range userIds {
		if len(id) != 26 {
			c.SetInvalidParam("user_id")
			return
		}
		if id == c.Session.UserId {
			found = true
		}
	}

	if !found {
		userIds = append(userIds, c.Session.UserId)
	}

	if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_CREATE_GROUP_CHANNEL) {
		c.SetPermissionError(model.PERMISSION_CREATE_GROUP_CHANNEL)
		return
	}

	if groupChannel, err := app.CreateGroupChannel(userIds, c.Session.UserId); err != nil {
		c.Err = err
		return
	} else {
		w.WriteHeader(http.StatusCreated)
		w.Write([]byte(groupChannel.ToJson()))
	}
}

func getChannel(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId()
	if c.Err != nil {
		return
	}

	channel, err := app.GetChannel(c.Params.ChannelId)
	if err != nil {
		c.Err = err
		return
	}

	if channel.Type == model.CHANNEL_OPEN {
		if !app.SessionHasPermissionToTeam(c.Session, channel.TeamId, model.PERMISSION_READ_PUBLIC_CHANNEL) {
			c.SetPermissionError(model.PERMISSION_READ_PUBLIC_CHANNEL)
			return
		}
	} else {
		if !app.SessionHasPermissionToChannel(c.Session, c.Params.ChannelId, model.PERMISSION_READ_CHANNEL) {
			c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
			return
		}
	}

	w.Write([]byte(channel.ToJson()))
	return
}

func getChannelUnread(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId().RequireUserId()
	if c.Err != nil {
		return
	}

	if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) {
		c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
		return
	}

	if !app.SessionHasPermissionToChannel(c.Session, c.Params.ChannelId, model.PERMISSION_READ_CHANNEL) {
		c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
		return
	}

	channelUnread, err := app.GetChannelUnread(c.Params.ChannelId, c.Params.UserId)
	if err != nil {
		c.Err = err
		return
	}

	w.Write([]byte(channelUnread.ToJson()))
}

func getChannelStats(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId()
	if c.Err != nil {
		return
	}

	if !app.SessionHasPermissionToChannel(c.Session, c.Params.ChannelId, model.PERMISSION_READ_CHANNEL) {
		c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
		return
	}

	memberCount, err := app.GetChannelMemberCount(c.Params.ChannelId)

	if err != nil {
		c.Err = err
		return
	}

	stats := model.ChannelStats{ChannelId: c.Params.ChannelId, MemberCount: memberCount}
	w.Write([]byte(stats.ToJson()))
}

func getPinnedPosts(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId()
	if c.Err != nil {
		return
	}

	if !app.SessionHasPermissionToChannel(c.Session, c.Params.ChannelId, model.PERMISSION_READ_CHANNEL) {
		c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
		return
	}

	if posts, err := app.GetPinnedPosts(c.Params.ChannelId); err != nil {
		c.Err = err
		return
	} else if HandleEtag(posts.Etag(), "Get Pinned Posts", w, r) {
		return
	} else {
		w.Header().Set(model.HEADER_ETAG_SERVER, posts.Etag())
		w.Write([]byte(posts.ToJson()))
	}
}

func getPublicChannelsForTeam(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireTeamId()
	if c.Err != nil {
		return
	}

	if !app.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_LIST_TEAM_CHANNELS) {
		c.SetPermissionError(model.PERMISSION_LIST_TEAM_CHANNELS)
		return
	}

	if channels, err := app.GetPublicChannelsForTeam(c.Params.TeamId, c.Params.Page*c.Params.PerPage, c.Params.PerPage); err != nil {
		c.Err = err
		return
	} else {
		w.Write([]byte(channels.ToJson()))
		return
	}
}

func getDeletedChannelsForTeam(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireTeamId()
	if c.Err != nil {
		return
	}

	if !app.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_MANAGE_TEAM) {
		c.SetPermissionError(model.PERMISSION_MANAGE_TEAM)
		return
	}

	if channels, err := app.GetDeletedChannels(c.Params.TeamId, c.Params.Page*c.Params.PerPage, c.Params.PerPage); err != nil {
		c.Err = err
		return
	} else {
		w.Write([]byte(channels.ToJson()))
		return
	}
}

func getPublicChannelsByIdsForTeam(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireTeamId()
	if c.Err != nil {
		return
	}

	channelIds := model.ArrayFromJson(r.Body)
	if len(channelIds) == 0 {
		c.SetInvalidParam("channel_ids")
		return
	}

	for _, cid := range channelIds {
		if len(cid) != 26 {
			c.SetInvalidParam("channel_id")
			return
		}
	}

	if !app.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_VIEW_TEAM) {
		c.SetPermissionError(model.PERMISSION_VIEW_TEAM)
		return
	}

	if channels, err := app.GetPublicChannelsByIdsForTeam(c.Params.TeamId, channelIds); err != nil {
		c.Err = err
		return
	} else {
		w.Write([]byte(channels.ToJson()))
	}
}

func getChannelsForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireUserId().RequireTeamId()
	if c.Err != nil {
		return
	}

	if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) {
		c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
		return
	}

	if !app.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_VIEW_TEAM) {
		c.SetPermissionError(model.PERMISSION_VIEW_TEAM)
		return
	}

	if channels, err := app.GetChannelsForUser(c.Params.TeamId, c.Params.UserId); err != nil {
		c.Err = err
		return
	} else if HandleEtag(channels.Etag(), "Get Channels", w, r) {
		return
	} else {
		w.Header().Set(model.HEADER_ETAG_SERVER, channels.Etag())
		w.Write([]byte(channels.ToJson()))
	}
}

func searchChannelsForTeam(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireTeamId()
	if c.Err != nil {
		return
	}

	props := model.ChannelSearchFromJson(r.Body)
	if props == nil {
		c.SetInvalidParam("channel_search")
		return
	}

	if !app.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_LIST_TEAM_CHANNELS) {
		c.SetPermissionError(model.PERMISSION_LIST_TEAM_CHANNELS)
		return
	}

	if channels, err := app.SearchChannels(c.Params.TeamId, props.Term); err != nil {
		c.Err = err
		return
	} else {
		w.Write([]byte(channels.ToJson()))
	}
}

func deleteChannel(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId()
	if c.Err != nil {
		return
	}

	var channel *model.Channel
	var err *model.AppError
	if channel, err = app.GetChannel(c.Params.ChannelId); err != nil {
		c.Err = err
		return
	}

	var memberCount int64
	if memberCount, err = app.GetChannelMemberCount(c.Params.ChannelId); err != nil {
		c.Err = err
		return
	}

	if channel.Type == model.CHANNEL_OPEN && !app.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_DELETE_PUBLIC_CHANNEL) {
		c.SetPermissionError(model.PERMISSION_DELETE_PUBLIC_CHANNEL)
		return
	}

	// Allow delete if there's only one member left in a private channel
	if memberCount > 1 && channel.Type == model.CHANNEL_PRIVATE && !app.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_DELETE_PRIVATE_CHANNEL) {
		c.SetPermissionError(model.PERMISSION_DELETE_PRIVATE_CHANNEL)
		return
	}

	err = app.DeleteChannel(channel, c.Session.UserId)
	if err != nil {
		c.Err = err
		return
	}

	c.LogAudit("name=" + channel.Name)

	ReturnStatusOK(w)
}

func getChannelByName(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireTeamId().RequireChannelName()
	if c.Err != nil {
		return
	}

	var channel *model.Channel
	var err *model.AppError

	if channel, err = app.GetChannelByName(c.Params.ChannelName, c.Params.TeamId); err != nil {
		c.Err = err
		return
	}

	if channel.Type == model.CHANNEL_OPEN {
		if !app.SessionHasPermissionToTeam(c.Session, channel.TeamId, model.PERMISSION_READ_PUBLIC_CHANNEL) {
			c.SetPermissionError(model.PERMISSION_READ_PUBLIC_CHANNEL)
			return
		}
	} else {
		if !app.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_READ_CHANNEL) {
			c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
			return
		}
	}

	w.Write([]byte(channel.ToJson()))
}

func getChannelByNameForTeamName(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireTeamName().RequireChannelName()
	if c.Err != nil {
		return
	}

	var channel *model.Channel
	var err *model.AppError

	if channel, err = app.GetChannelByNameForTeamName(c.Params.ChannelName, c.Params.TeamName); err != nil {
		c.Err = err
		return
	}

	if !app.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_READ_CHANNEL) {
		c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
		return
	}

	w.Write([]byte(channel.ToJson()))
	return
}

func getChannelMembers(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId()
	if c.Err != nil {
		return
	}

	if !app.SessionHasPermissionToChannel(c.Session, c.Params.ChannelId, model.PERMISSION_READ_CHANNEL) {
		c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
		return
	}

	if members, err := app.GetChannelMembersPage(c.Params.ChannelId, c.Params.Page, c.Params.PerPage); err != nil {
		c.Err = err
		return
	} else {
		w.Write([]byte(members.ToJson()))
	}
}

func getChannelMembersByIds(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId()
	if c.Err != nil {
		return
	}

	userIds := model.ArrayFromJson(r.Body)
	if len(userIds) == 0 {
		c.SetInvalidParam("user_ids")
		return
	}

	if !app.SessionHasPermissionToChannel(c.Session, c.Params.ChannelId, model.PERMISSION_READ_CHANNEL) {
		c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
		return
	}

	if members, err := app.GetChannelMembersByIds(c.Params.ChannelId, userIds); err != nil {
		c.Err = err
		return
	} else {
		w.Write([]byte(members.ToJson()))
	}
}

func getChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId().RequireUserId()
	if c.Err != nil {
		return
	}

	if !app.SessionHasPermissionToChannel(c.Session, c.Params.ChannelId, model.PERMISSION_READ_CHANNEL) {
		c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
		return
	}

	if member, err := app.GetChannelMember(c.Params.ChannelId, c.Params.UserId); err != nil {
		c.Err = err
		return
	} else {
		w.Write([]byte(member.ToJson()))
	}
}

func getChannelMembersForUser(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireUserId().RequireTeamId()
	if c.Err != nil {
		return
	}

	if !app.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_VIEW_TEAM) {
		c.SetPermissionError(model.PERMISSION_VIEW_TEAM)
		return
	}

	if c.Session.UserId != c.Params.UserId && !app.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_MANAGE_SYSTEM) {
		c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
		return
	}

	if members, err := app.GetChannelMembersForUser(c.Params.TeamId, c.Params.UserId); err != nil {
		c.Err = err
		return
	} else {
		w.Write([]byte(members.ToJson()))
	}
}

func viewChannel(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireUserId()
	if c.Err != nil {
		return
	}

	if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) {
		c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
		return
	}

	view := model.ChannelViewFromJson(r.Body)
	if view == nil {
		c.SetInvalidParam("channel_view")
		return
	}

	if err := app.ViewChannel(view, c.Params.UserId, !c.Session.IsMobileApp()); err != nil {
		c.Err = err
		return
	}

	ReturnStatusOK(w)
}

func updateChannelMemberRoles(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId().RequireUserId()
	if c.Err != nil {
		return
	}

	props := model.MapFromJson(r.Body)

	newRoles := props["roles"]
	if !(model.IsValidUserRoles(newRoles)) {
		c.SetInvalidParam("roles")
		return
	}

	if !app.SessionHasPermissionToChannel(c.Session, c.Params.ChannelId, model.PERMISSION_MANAGE_CHANNEL_ROLES) {
		c.SetPermissionError(model.PERMISSION_MANAGE_CHANNEL_ROLES)
		return
	}

	if _, err := app.UpdateChannelMemberRoles(c.Params.ChannelId, c.Params.UserId, newRoles); err != nil {
		c.Err = err
		return
	}

	ReturnStatusOK(w)
}

func updateChannelMemberNotifyProps(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId().RequireUserId()
	if c.Err != nil {
		return
	}

	props := model.MapFromJson(r.Body)
	if props == nil {
		c.SetInvalidParam("notify_props")
		return
	}

	if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) {
		c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
		return
	}

	_, err := app.UpdateChannelMemberNotifyProps(props, c.Params.ChannelId, c.Params.UserId)
	if err != nil {
		c.Err = err
		return
	}

	ReturnStatusOK(w)
}

func addChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId()
	if c.Err != nil {
		return
	}

	member := model.ChannelMemberFromJson(r.Body)
	if member == nil {
		c.SetInvalidParam("channel_member")
		return
	}

	if len(member.UserId) != 26 {
		c.SetInvalidParam("user_id")
		return
	}

	member.ChannelId = c.Params.ChannelId

	var channel *model.Channel
	var err *model.AppError
	if channel, err = app.GetChannel(member.ChannelId); err != nil {
		c.Err = err
		return
	}

	// Check join permission if adding yourself, otherwise check manage permission
	if channel.Type == model.CHANNEL_OPEN {
		if member.UserId == c.Session.UserId {
			if !app.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_JOIN_PUBLIC_CHANNELS) {
				c.SetPermissionError(model.PERMISSION_JOIN_PUBLIC_CHANNELS)
				return
			}
		} else {
			if !app.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS) {
				c.SetPermissionError(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS)
				return
			}
		}
	}

	if channel.Type == model.CHANNEL_PRIVATE && !app.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS) {
		c.SetPermissionError(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS)
		return
	}

	if cm, err := app.AddChannelMember(member.UserId, channel, c.Session.UserId); err != nil {
		c.Err = err
		return
	} else {
		c.LogAudit("name=" + channel.Name + " user_id=" + cm.UserId)
		w.WriteHeader(http.StatusCreated)
		w.Write([]byte(cm.ToJson()))
	}
}

func removeChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
	c.RequireChannelId().RequireUserId()
	if c.Err != nil {
		return
	}

	var channel *model.Channel
	var err *model.AppError
	if channel, err = app.GetChannel(c.Params.ChannelId); err != nil {
		c.Err = err
		return
	}

	if c.Params.UserId != c.Session.UserId {
		if channel.Type == model.CHANNEL_OPEN && !app.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS) {
			c.SetPermissionError(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS)
			return
		}

		if channel.Type == model.CHANNEL_PRIVATE && !app.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS) {
			c.SetPermissionError(model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS)
			return
		}
	}

	if err = app.RemoveUserFromChannel(c.Params.UserId, c.Session.UserId, channel); err != nil {
		c.Err = err
		return
	}

	c.LogAudit("name=" + channel.Name + " user_id=" + c.Params.UserId)

	ReturnStatusOK(w)
}


This is a placeholder page for Jacob Buxton, which means this person is not currently on this site. We do suggest using the tools below to find Jacob Buxton.
You are visiting the placeholder page for Jacob Buxton. This page is here because someone used our placeholder utility to look for Jacob Buxton. We created this page automatically in hopes Jacob Buxton would find it. If you are not Jacob Buxton, but are an alumni of Lake Orion High School, register on this site for free now.


text:
Virtual Doorman ®
Reception Management
Door Guard
Electronic Key Safe
Virtual Guard
Self-Managed Access Control
Electronic Card Access
Color Video Intercoms
Aiphone Security Products
Siedle Vario Products
Comelit Products
CCTV & Digital Video
March Networks 7532 Hybrid NVR
March Network 4324C/4332C Hybrid NVR
March Networks 4000C Series NVR
Museums & Libraries
Why Virtual Service
Awards & Expertise
Longchamp USA
Maimonides Medical Ctr (CCTV)
Maimonides Medical Ctr (Access Control)
The Bridges At 2279 3rd Avenue
8 Union Square South
165 Charles Street
Please email us 24/7 at
support@virtualservice.net
Sales: info@virtualservice.net
Support: support@virtualservice.net
Pricing & Info: 844.228.1112
Case Study: 8 Union Square South
Client Testimonial:
"Virtual Service's security system helped increase the value and marketability of our building while decreasing our overall labor costs."
John Lari
The Claremont Group
16 x cameras 2 x DVR
5 doors of card access
Virtual Doorman System
16 x cameras
2 x DVR
Virtual Service Secures Luxury High-Rise Condominium
Although an encrypted card access system was not required to make tenants at developer John Lari's new luxury building feel secure, he chose to go over and above in his latest residential project at 8 Union Square South. The state-of-the-art system installed by Virtual Service not only secures the building's entrance, but also provides the necessary elevator floor lockout security for the large, national bank which inhabits the building's ground level commercial space that shares the common elevator. With a bank as the commercial tenant, there is no room for the slightest error with building security.
For additional convenience and safety, the system also logs every door accessed and card used. In the event of a lost or stolen card, the system can be administered remotely and the card can be deleted. A replacement card specific to the tenant can be activated in a matter of seconds by Virtual Service. Virtual Service manages the tenant information and access rights, eliminating the cost of training building staff or management on such a sophisticated system. By doing so, tenants are provided with a higher level of security because all cards are issued and managed by Virtual Service. The system can also be configured to allow limited and supervised access for delivery services, maintenance and domestic staff.
The building also features a multi-camera CCTV system with a digital video recorder. The enterprise level recorder is currently used by clients such as San Francisco Municipal Railway's Light Rail, Wachovia Bank, the Lake Pontchartrain Causeway and Miami-Dade Transit. In today's competitive real estate market, unique features such as the ones at 8 Union Square South are critical for developers in order to ensure that their property will stand out from the crowd to prospective buyers. Tenants are willing to pay the extra premium for an apartment in a building where the security system makes them feel safe and comfortable.
The challenges for Virtual Service at 8 Union Square South were twofold. The first was its unique "sky lobby" area on the second floor of the building. During the day, the building's doorman attends the small lobby on the first floor and greets visitors and tenants. In the evening, the doorman periodically relocates to the second floor's larger "sky lobby". From both positions, he is able to monitor the building's camera system. When in the upstairs lobby, the infrared beam in the building vestibule alerts him of a visitor and displays the associated camera so that he is aware of activity downstairs. This allows the doorman to provide services to the tenants in the sky lobby while still able to handle delivery persons entering downstairs. From both lobby positions, the doorman can release the elevator and allow delivery persons or guests access to tenant's specific floors without unlocking the entire elevator and granting access to the bank's space. In order to expedite a delivery, the doorman can speak with a person at the first floor lobby and remotely grant them access to the tenant's floor from their position in the second floor lobby.
The second challenge was that Virtual Service faced was having to interface with multiple contractors and sub-contractors throughout the installation as multiple parties were responsible for various phases during construction. Virtual Service consulted with the Claremont Group from the beginning of the project in order to ensure that the other contractors provided the necessary hardware and device interfaces that were required to make the system function as desired. Virtual Service project managed the security system installation and provided the various contractors with the necessary schematics and diagrams to be able to complete their work. Doing so ensured that the project stayed on track and completed successfully, saving the developer money and aggravation.
Virtual Doorman®
CCTV & Digital Video Products
Virtual Service has gone over and above to provide us with superior service and then gone a little bit further whenever possible. We highly recommend them and look forward to continued service from them in the future.
Nick Coslov
I am pleased to say that the system and service worked as Andy explained during the initial sales meetings. I was so pleased with the service and solution that Virtual provided that I recommended them to the owner of the building.
David Kriss
I am writing to commend you for the exceptional service and support that Leboeuf Lamb Greene & MacRae has received from you during the implementation of our video conferencing systems. The technology has been extremely beneficial to our firm.
Leslie Vander Wyden
A division of Virtual Service™

redpajama_set_name: RedPajamaCommonCrawl


Head pin, gunmetal-plated brass, 1 inch, 24 gauge. Sold per pkg of 100.
Item Number: H20-9534FX Have a question about this item?
Brass-based head pins have a popular gunmetal plating, adding long-lasting shine and tarnish resistance. The neutral gray finish is a crowd-pleasing addition to jewelry designs.
Head pin, gunmetal-plated brass, 1 inch, 24 gauge. Sold per pkg of 500.


1. Sign in to Twibes.
2. Visit the twibe page you want to leave.
3. On the right-hand sidebar under the number of members, you should see a link that reads, "Leave the twibe." Click on this link.
4. When the page refreshes, you are removed from the twibe.


Last night the Tampa City Council gave preliminary approval for the Residences at the Riverwalk, the proposed 36 story apartment tower smack in the middle of the performing arts district, adjacent to the Straz Performing Arts Center and the northern reach of the Tampa Riverwalk.
Council members voted 5-2 to rezone the acre of city-owned land west of the John F. Germany Library where the tower will stand. They also approved a city request to vacate ownership of Tyler and Cass streets within the tower footprint.
The proposal drew a packed house for a hearing that ran more than three hours. The final vote will be at 9:30 a.m. Aug. 22.
The parcel of land is currently owned by the city of Tampa. This tower will be crammed in a one acre parcel being sold by the city of Tampa for $4 million to the developer, a price above the appraised value. In turn, the developers will donate an unrestricted $1 million to the Straz, whose board originally opposed the tower.
Actually, that parcel is really not there, it will have to be created. They will have to reroute Tyler and Cass streets, change them from one-way to two-way streets, reconfigure the Straz drop off area where Tyler will now dead end, in order to create that one acre of space.
The new tower will be about 500 feet tall, in the arts district (considered west of Ashley), where there is no other residential or commercial development. It will be about 3 times taller than the Straz itself, hence the vote on the zoning change to allow the out of place, high rise tower. 380 residences are planned along with about 10,000 square feet of retail space. Estimates are they'll be able to stack and pack 500 people in that one acre.
We at the Eye went down to the area and took a look around to see for ourselves to try to understand how they'll shoehorn this thing in.
The Riverwalk vision was as a linear park along the river for Tampa citizens to enjoy and be aesthetically appealing, which we at the Eye have enjoyed personally. Will we now get a Canyon of Towers instead?


text:
Welsh Air Ambulance Charitable Trust
Cymraeg Contact us Donate
Charity Confusion Clarification
Patron and ambassadors
Our bases
Medics and kit
Children's Wales Air Ambulance
Meet the PR Team
Caffi HEMS
Donate your pre-loved items
Why leave a gift
How your gift can help
How to leave a gift in your Will
Free will writing service
Will FAQs
Create fundraising page
About corporate giving
About our lottery
Lottery FAQs
Gambling Policy
Aldi Helps To Fill Charity Shop Shelves
Wales Air Ambulance has teamed up with the UK's fastest growing and fifth largest supermarket, Aldi, to help fill the shelves of the charity's shops across Wales.
The supermarket chain recently donated stock from their famous Specialbuys, worth in excess of £20,000, which has been distributed across the air ambulance charity's 17 shops.
Talking about the donation of stock, Wales Air Ambulance Warehouse and Transport Manager, Rhys Richards said: "We are incredibly grateful to Aldi for the support they have shown us. The stock donated has ranged from bedding to tools and outdoor equipment. The variety of items has enabled us to offer a greater choice to our customers, which has proved very popular.
"With over 8,000 items donated to us, we would not have been able to benefit from them without the help of transport company Trailermech. They kindly stepped in to help us transport the stock to our Swansea warehouse. Without the help of David Baker and the team at Trailermech, none of this would have been possible, we owe them a great deal of gratitude."
Annually, Wales Air Ambulance needs to raise £6.5 million to keep the four helicopters flying. With the charity attending on average 2,500 missions each year, every donation supports the lifesaving service.
Dan Oakenfull, Regional Managing Director for Aldi UK, said: "It was a pleasure to donate some of our Specialbuys to Wales Air Ambulance, who have been able to distribute it across Wales and raise money to reach their yearly target.
"The team at Wales Air Ambulance do a fantastic job, and we're really pleased we've been able to support them with the range of stock we have donated".
Wales Air Ambulance Head of Retail and Trading, Andrew Lawton said: "This really is a unique partnership between us and one of the UK's largest supermarket chains. To be able to rely on Aldi's support really is special for us as an air ambulance charity. With each mission costing on average £1,500, the stock donated to us has already helped fund our lifesaving work. We can't thank them enough for supporting our cause."
Wales Air Ambulance has 17 shops located across Wales, including the newest Children's Wales Air Ambulance store located in the heart of the Welsh capital. Each one of the shops is supported by a team of dedicated volunteers who partake in filling the shelves, assisting with customer enquiries and helping to raise vital funds. The charity's shops are a key source of income, which contributes significantly to reaching the yearly target of £6.5 million.
Author: Gareth Hurford
We will always store your personal details securely. We'll use them to provide the service that you have requested, and communicate with you in the way(s) that you have agreed to. Your data may also be used for analysis purposes, to help us provide the best service possible. For full details see our Privacy Policy.
Welcome to our website. If you continue to browse and use this website, you are agreeing to comply with and be bound by the following terms and conditions of use, which together with our privacy policy govern Wales Air Ambulance's relationship with you in relation to this website. If you disagree with any part of these terms and conditions, please do not use our website. The term 'Wales Air Ambulance' or 'WAA' or 'Welsh Air Ambulance Charitable Trust' or 'us' or 'we' refers to the owner of the website whose registered office is Ty Elusen, Ffordd Angel, Llanelli Gate, Dafen. SA14 8LQ. Our registered charity number is 1083645. The term 'you' refers to the user or viewer of our website. The use of this website is subject to the following terms of use: - The content of the pages of this website is for your general information and use only. It is subject to change without notice. - Neither we nor any third parties provide any warranty or guarantee as to the accuracy, timeliness, performance, completeness or suitability of the information and materials found or offered on this website for any particular purpose. You acknowledge that such information and materials may contain inaccuracies or errors and we expressly exclude liability for any such inaccuracies or errors to the fullest extent permitted by law. - Your use of any information or materials on this website is entirely at your own risk, for which we shall not be liable. It shall be your own responsibility to ensure that any products, services or information available through this website meet your specific requirements. - This website contains material which is owned by or licensed to us. This material includes, but is not limited to, the design, layout, look, appearance and graphics. Reproduction is prohibited other than in accordance with the copyright notice, which forms part of these terms and conditions. - Unauthorised use of this website may give rise to a claim for damages and/or be a criminal offence. - From time to time, this website may also include links to other websites. These links are provided for your convenience to provide further information. They do not signify that we endorse the website(s). We have no responsibility for the content of the linked website(s). - Your use of this website and any dispute arising out of such use of the website is subject to the laws of England, Northern Ireland, Scotland and Wales. We use cookies on our website and may collect personal information from you when you use our website. Please read our full Privacy Policy. Website Disclaimer: The information contained in this website is for general information purposes only. The information is provided by Wales Air Ambulance and while we endeavour to keep the information up to date and correct, we make no representations or warranties of any kind, express or implied, about the completeness, accuracy, reliability, suitability or availability with respect to the website or the information, products, services, or related graphics contained on the website for any purpose. Any reliance you place on such information is therefore strictly at your own risk. In no event will we be liable for any loss or damage including without limitation, indirect or consequential loss or damage, or any loss or damage whatsoever arising from loss of data or profits arising out of, or in connection with, the use of this website. Through this website, you are able to link to other websites which are not under the control of Wales Air Ambulance. We have no control over the nature, content, and availability of those sites. The inclusion of any links does not necessarily imply a recommendation or endorse the views expressed within them. Every effort is made to keep the website up and running smoothly. However, Wales Air Ambulance takes no responsibility for, and will not be liable for, the website being temporarily unavailable due to technical issues beyond our control. Website Privacy Policy: We use cookies on our website and may collect personal information from you when you use our website. Please read our full Privacy Policy here. Website terms of use: The use of this website is subject to the following terms of use: The content of the pages of this website is for your general information and use only. It is subject to change without notice. Neither we nor any third parties provide any warranty or guarantee as to the accuracy, timeliness, performance, completeness or suitability of the information and materials found or offered on this website for any particular purpose. You acknowledge that such information and materials may contain inaccuracies or errors and we expressly exclude liability for any such inaccuracies or errors to the fullest extent permitted by law. Your use of any information or materials on this website is entirely at your own risk, for which we shall not be liable. It shall be your own responsibility to ensure that any products, services or information available through this website meet your specific requirements. This website contains material which is owned by or licensed to us. This material includes, but is not limited to, the design, layout, look, appearance and graphics. Reproduction is prohibited other than in accordance with the copyright notice, which forms part of these terms and conditions. Unauthorised use of this website may give rise to a claim for damages and/or be a criminal offence. From time to time, this website may also include links to other websites. These links are provided for your convenience to provide further information. They do not signify that we endorse the website(s). We have no responsibility for the content of the linked website(s). Your use of this website and any dispute arising out of such use of the website is subject to the laws of England, Northern Ireland, Scotland and Wales.
Sue Lawson Sky Dive
Wales Air Ambulance air lifted a little boy to the Heath after a road accident. His mum holds a very special place in our hearts and this is a small way of thanking her for all the care, love and support she gave to our family.
Air Tastes Beautiful
Your helicopter picked me up and took me to Stoke hospital. Suffered spinal injury and am high-level tetraplegic.
PENYBONT GRAND TOUR
PENYBONT TO GIBRALTAR IN A £500 BRITISH BANGER
How many will make it?
The Challenge – to make it to Gibraltar!
Charity Café Nominated for Inaugural Welsh Café Award
A café that supports the lifesaving work of the Wales Air Ambulance (WAA) has been shortlisted for an award at the inaugural Welsh Café Awards 2019.
Wales' most expensive Gin just the tonic for charity
A unique gin that made history by being the first to be distilled at the top of Mount Snowdon has sold at a charity auction for Wales Air Ambulance, becoming Wales' most expensive gin in the process.
Wales Air Ambulance pilots and engineers recognised with international award
The exceptional work of the Wales Air Ambulance pilots and engineers was recognised during a prestigious international aviation awards ceremony in Paris, recently.
Wales Air Ambulance calls out for votes to bag a share of Tesco's community fund
Wales Air Ambulance is bidding to bag a massive cash boost from the Tesco Bags of Help Centenary Grant initiative.
Wales Air Ambulance Auctions Rare Welsh Gin
Gin fans are in for a treat this weekend as the highest distilled gin in the UK goes under auction to help raise vital funds for Wales Air Ambulance.
Children's Wales Air Ambulance fondly remembers South Wales Midwife
Family and Friends of a former South Wales midwife have paid tribute to her following a donation made to Wales Air Ambulance.
By Order of the Peaky Fundraisers
A Swansea fundraising event has raised a considerable amount of money for Wales Air Ambulance.
Thank you to the Darth Sponsors
After another very successful Darth Mannion Beath & Swamp Run this year, Wales Air Ambulance would like to say a huge thank you to all the sponsors who kindly donated prizes to the raffle and auction.
Remembering Desmond Edward Jenkins
Friends of the late Desmond Edward Jenkins have paid tribute to the man who has left a substantial lifesaving legacy to the Wales Air Ambulance Charity.
Children's Wales Air Ambulance Shop Lands in Welsh Capital
Wales Air Ambulance (WAA) has officially opened its newest charity shop in the heart of the Welsh capital.
Elin Murphy
Community Coordinator for Carmarthenshire
Let your legacy live on through saving the life of another.
Your pre-loved items could help save a life!
About our Lifesaving Lottery
Join our Lifesaving Lottery!
Serving Wales, Saving Lives
Every year our crew attend over 2,500 missions
Keep a look out for our forthcoming newsletter!
Full sitemap
Ty Elusen, Ffordd Angel, Llanelli Gate, Dafen, Llanelli. SA14 8LQ
Caernarfon Airport, Dinas Dinlle, Caernarfon. LL54 5TP
Registration Charity Number: 1083645. Copyright © 2018


HKK British Standard chain is manufactured to the same high quality specifications as our ANSI chain. Solid bushings and solid rollers dramatically increase chain life. Manufactured in accordance with ISO R606, HKK British standard chains are compatible with British standard B.S. 228 and German standard DIN 8187. Chains are supplied in 10-foot lengths. Attachment chains and stainless steel chains are available.


text:
Q: WPF TextBox input filtering doesn't work as expected with a decimal I am trying to filter the input to a WPF TextBox to prevent the user from entering non-numerical strings. I have configured PreviewKeyDown and am checking the characters entered with the code from this question to convert the key codes to characters. Everything works as expected except when the user enters a period. The code does detect a period was entered, yet when I return from PreviewKeyDown with setting KeyEventArgs's Handled to false, it doesn't allow the period to be entered.
XAML
<TextBox PreviewKeyDown="TextBox_PreviewKeyDown">
    <TextBox.Text>
        <Binding Source="{StaticResource SomeObject}" Path="SomePath" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:MyValidationRule/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

C#
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
    char character = GetCharFromKey(e.Key);

    e.Handled = false;
    if (character >= '0' && character <= '9')
        return;
    if (character == '.')
        return;
    switch(e.Key)
    {
        case Key.Delete:
        case Key.Back:
            return;
    }
    e.Handled = true;
}

A: Can't you handle the PreviewTextInput event? Something like this:
private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    string str = ((TextBox)sender).Text + e.Text;
    decimal i;
    e.Handled = !decimal.TryParse(str, System.Globalization.NumberStyles.AllowDecimalPoint, System.Globalization.CultureInfo.InvariantCulture, out i);
}

XAML:
<TextBox Text="{Binding SomePath}" PreviewTextInput="TextBox_PreviewTextInput" />

Edit: The problem with using a an UpdateSourceTrigger of PropertyChanged is that the string "5." gets converted to 5M and that's the value that you see in the TextBox. The "5." string is not stored somewhere.
You could possible overcome this by using a converter that keeps track of the latest known string:
public class DecimalToStringConverter : IValueConverter
{
    private string _lastConvertedValue;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return _lastConvertedValue ?? value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string str = value?.ToString();
        decimal d;
        if (decimal.TryParse(str, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out d))
        {
            _lastConvertedValue = str;
            return d;
        }

        _lastConvertedValue = null;
        return Binding.DoNothing;
    }
}

XAML:
<TextBox PreviewTextInput="TextBox_PreviewTextInput">
    <TextBox.Text>
        <Binding Path="SomePath" UpdateSourceTrigger="PropertyChanged">
            <Binding.Converter>
                <local:DecimalToStringConverter />
            </Binding.Converter>
        </Binding>
    </TextBox.Text>
</TextBox>

A: I have a behaviour I use for this, I think it's based on something I got off the web. You could just use it as is, or work out why your version isn't working.  Note the code handles pasting in though.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace UILib
{
    public class TextBoxDecimalRangeBehaviour : Behavior<TextBox>
    {
        public string EmptyValue { get; set; } = "0";

        public double Minimum
        {
            get { return (double)GetValue(MinimumProperty); }
            set { SetValue(MinimumProperty, value); }
        }
        public static readonly DependencyProperty MinimumProperty =
            DependencyProperty.Register("Minimum", typeof(double), typeof(TextBoxDecimalRangeBehaviour), new PropertyMetadata(0.0));

        public double Maximum
        {
            get { return (double)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }
        public static readonly DependencyProperty MaximumProperty =
            DependencyProperty.Register("Maximum", typeof(double), typeof(TextBoxDecimalRangeBehaviour), new PropertyMetadata(10.0));

        public int MaxInteger
        {
            get { return (int)GetValue(MaxIntegerProperty); }
            set { SetValue(MaxIntegerProperty, value); }
        }
        public static readonly DependencyProperty MaxIntegerProperty =
            DependencyProperty.Register("MaxInteger", typeof(int), typeof(TextBoxDecimalRangeBehaviour), new PropertyMetadata(1));

        public int MaxDecimals
        {
            get { return (int)GetValue(MaxDecimalsProperty); }
            set { SetValue(MaxDecimalsProperty, value); }
        }

        public static readonly DependencyProperty MaxDecimalsProperty =
            DependencyProperty.Register("MaxDecimals", typeof(int), typeof(TextBoxDecimalRangeBehaviour), new PropertyMetadata(2));

        /// <summary>
        ///     Attach our behaviour. Add event handlers
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();

            AssociatedObject.PreviewTextInput += PreviewTextInputHandler;
            AssociatedObject.PreviewKeyDown += PreviewKeyDownHandler;
            DataObject.AddPastingHandler(AssociatedObject, PastingHandler);
        }

        /// <summary>
        ///     Deattach our behaviour. remove event handlers
        /// </summary>
        protected override void OnDetaching()
        {
            base.OnDetaching();

            AssociatedObject.PreviewTextInput -= PreviewTextInputHandler;
            AssociatedObject.PreviewKeyDown -= PreviewKeyDownHandler;
            DataObject.RemovePastingHandler(AssociatedObject, PastingHandler);
        }

        void PreviewTextInputHandler(object sender, TextCompositionEventArgs e)
        {
            string text;
            if (this.AssociatedObject.Text.Length < this.AssociatedObject.CaretIndex)
                text = this.AssociatedObject.Text;
            else
            {
                //  Remaining text after removing selected text.
                string remainingTextAfterRemoveSelection;

                text = TreatSelectedText(out remainingTextAfterRemoveSelection)
                    ? remainingTextAfterRemoveSelection.Insert(AssociatedObject.SelectionStart, e.Text)
                    : AssociatedObject.Text.Insert(this.AssociatedObject.CaretIndex, e.Text);
            }

            e.Handled = !ValidateText(text);
        }

        /// <summary>
        ///     PreviewKeyDown event handler
        /// </summary>
        void PreviewKeyDownHandler(object sender, KeyEventArgs e)
        {
            if (string.IsNullOrEmpty(this.EmptyValue))
            {
                return;
            }

            string text = null;

            // Handle the Backspace key
            if (e.Key == Key.Back)
            {
                if (!this.TreatSelectedText(out text))
                {
                    if (AssociatedObject.SelectionStart > 0)
                        text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart - 1, 1);
                }
            }
            // Handle the Delete key
            else if (e.Key == Key.Delete)
            {
                // If text was selected, delete it
                if (!this.TreatSelectedText(out text) && this.AssociatedObject.Text.Length > AssociatedObject.SelectionStart)
                {
                    // Otherwise delete next symbol
                    text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart, 1);
                }
            }

            if (text == string.Empty)
            {
                this.AssociatedObject.Text = this.EmptyValue;
                if (e.Key == Key.Back)
                    AssociatedObject.SelectionStart++;
                e.Handled = true;
            }
        }

        private void PastingHandler(object sender, DataObjectPastingEventArgs e)
        {
            if (e.DataObject.GetDataPresent(DataFormats.Text))
            {
                string text = Convert.ToString(e.DataObject.GetData(DataFormats.Text));

                if (!ValidateText(text))
                    e.CancelCommand();
            }
            else
                e.CancelCommand();
        }

        /// <summary>
        ///     Validate certain text by our regular expression and text length conditions
        /// </summary>
        /// <param name="text"> Text for validation </param>
        /// <returns> True - valid, False - invalid </returns>
        private bool ValidateText(string text)
        {
            double number;
            if (!Double.TryParse(text, out number))
            {
                return false;
            }
            if(number < Minimum)
            {
                return false;
            }
            if (number > Maximum)
            {
                return false;
            }
            int dotPointer = text.IndexOf('.');
            // No point entered so the decimals must be ok
            if(dotPointer == -1)
            {
                return true;
            }
            if (dotPointer > MaxInteger)
            {
                return false;
            }
            if(text.Substring(dotPointer +1).Length > MaxDecimals)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        ///     Handle text selection
        /// </summary>
        /// <returns>true if the character was successfully removed; otherwise, false. </returns>
        private bool TreatSelectedText(out string text)
        {
            text = null;
            if (AssociatedObject.SelectionLength <= 0)
                return false;

            var length = this.AssociatedObject.Text.Length;
            if (AssociatedObject.SelectionStart >= length)
                return true;

            if (AssociatedObject.SelectionStart + AssociatedObject.SelectionLength >= length)
                AssociatedObject.SelectionLength = length - AssociatedObject.SelectionStart;

            text = this.AssociatedObject.Text.Remove(AssociatedObject.SelectionStart, AssociatedObject.SelectionLength);
            return true;
        }
    }
}

Usage:
<TextBox Text="{Binding ......>
    <i:Interaction.Behaviors>
        <ui:TextBoxDecimalRangeBehaviour MaxDecimals="2"
                                         MaxInteger="1"
                                         Minimum="{StaticResource Zero}"
                                         Maximum="{StaticResource Ten}" />
        <ui:SelectAllTextBoxBehavior/>
    </i:Interaction.Behaviors>
</TextBox>

redpajama_set_name: RedPajamaStackExchange


text:
To support the fight against the drought, the Cabinet will forfeit one month's pay.
November 30, 2022 Legal Spy 0
File image of the Parliament buildings in Nairobi. [Photo | Courtesy]
The Cabinet of President William Ruto has decided to contribute to the nation's efforts to mitigate the effects of the drought by forgoing one month's pay.
This was made public on Tuesday during the third Cabinet meeting, which President Ruto presided over at State House in Nairobi and covered a range of policy topics, including an evaluation of the effectiveness of the drought mitigation measures put in place.
The recently established National Drought Response Steering Committee, which is led by Peter Ndegwa, CEO of Safaricom, was praised at the Cabinet meeting, according to a statement distributed to newsrooms.
Peter Ndegwa, CEO of Safaricom, named by Ruto to lead the…
Safaricom Set To Remove 4 Million Customers From CRB
The communiqué stated that "the nation's top policy-making body was also informed on the progress made in tackling the effects of the ongoing drought in several sections of the country."
The National Steering Committee on Drought Response's sponsorship of the expanding relationship between the State, Development Partners, and the country's commercial sector was applauded at the conference.
"The meeting determined that all Members will forgo one month's salary as their individual and collective contribution towards the continuing State initiatives that benefit all Kenyans afflicted by the drought," the statement continued.
Dramatic Arrest of Ex-Turkana CEC by EACC Detectives as Goons Save Him
Five alleged muggers arrested in Starehe


These days, you can find a DJ spinning for a corporate training luncheon as easily as you could a dive bar off of the Strip. However, it takes an experienced disc jockey to not only get the party started, but keep it going all night long.
Unfortunately, nowadays DJs remain a dime a dozen, especially as anyone can get started with a laptop and some speakers. When you need to maintain a lively atmosphere for any occasion, there is no substitute for experience. Can you imagine what a horrible thing it would be to hire a terrible wedding DJ for that lifetime celebration? With LV Events DJ, you never have to worry about that. We want you to focus on other parts of the event, rather than worrying about the disc jockey.
Las Vegas Events DJ continues bringing the excitement to any event with more than 30 years of continued industry experience. No one else keeps Las Vegas, NV on its feet like DJ Chucky Brown.
No matter what the reason for your party, we ensure that it stays going as long as you need. When you don't want the fun to stop until the sun comes up, you need us keeping the beats coming.
The problem in finding your ideal disc jockey for an event is that they all claim to be the best. Maybe it's ego, or perhaps they think you're supposed to from listening to top 40 hip-hop and bubblegum rap.
However, there's no denying the pedigree and skill that you can have for your upcoming event. Over the past 30 years, we've DJ'ed for anyone and everyone, including Alex Rodriguez, Elton John, MTV, VH1, and the cast of Hamilton, just to name a few.
And if you're worried about going to the same party you went to last week, fear not. DJ Chucky Brown has no set list. He only spins what the crowd happens to feel in the moment.
Whether you have a new favorite song you need to hear or you just want to experience the best DJ around, we remain available for all your party needs. Call to make your event its best with the top name in entertainment today.
With many live music service providers, you can get by with a few speakers and play music on your phone. That is because they adhere to the same tracks that they play at every event that they get hired.
Other DJs maintain a collection of tracks and albums that they haven't updated in 15 years, while others still play the current top 40 singles and little else. When you need to keep the party going, it helps when the crowd stays on their toes. Just view our galleries on our wedding page and special events page.
We can make any venue look, feel, and sound the way that you need it to, from traditional wedding ceremonies to unique costumed parties. Contact Us to keep the crowd moving for your upcoming events.
We service the Las Vegas and San Francisco areas. Please inquire about other cities.
While we can offer many other services like many other Disc Jockey companies do, we like to stay focused on DJing to provide a seamless experience. Please see our services below and click to see which best fits the event you are looking to hire us for. Contact us to discuss more in detail and to get a quote.


Every time I boot up my pc I get a notification "finish installing device software" under the category "security and maintenance". If I click on the notification the notification disappears and nothing happens. If I go to control panel/security and maintenance and click on the install button for this notification the notification disappears and nothing happens. Either way the notification comes back the next time I boot up. I updated the video driver to the latest version from nvidia and that wasn't it. Is there a way to determine from which app this notification is originating from?
Hope this information helps. Do get back to us with the updated status. We will be happy to assist you further.
I followed your instructions and the result was "no changes or updates were necessary", yet the notification still pops up in the action center.
November update broke something and I tried re-installing the drivers, 3 times.
Then this message kept popping up in the update section.
It's gone now, and so is my hope that this will ever be resolved.
When you click on the "Finish installing device software" message, open the file "C:\Windows\INF\setupapi.dev" using Notepad.
It should tell you which driver was last updated using the "Finish-Install" action and thus which driver is causing the issue.
How about open the file "C:\Windows\INF\setupapi.dev.log"? All statuses here are "SUCCESS".
I had this on a new Windows 10 laptop, nothing had failed to install & after restarting nothing changed, I have run the USB device cleaner under IOBit's device manager but no change, I have lived with it for over a year until I did a clean install of the creators update recently. Now no error message.
In my current Win10 user-interface, there's no "View All" option in the "Troubleshoot" submenu of "Settings". However I'm not so easily dismayed by the ever-changing Win10 UI... eventually I stumbled across Settings/Troubleshoot/Hardware and Devices -- which offered me the option "Run the troubleshooter". This troubleshooter is -- I suspect -- a version of the troubleshooter Jenith is referring to, and it quickly identified something which seems likely to be an incomplete installation of a device driver.
I pity the devs around the world who struggle to keep up with the ongoing product-churn of the "Windows 10" branded operating systems! And it's an ongoing struggle for those of us in user-land to keep up with (I'm sure) the very-well-intentioned Win10 developers who continue to shift things around in the UI of this beast. I haven't yet discovered whether enabling this adapter (which doesn't seem to be necessary to my use of Cisco AnyConnect) will have any (easily discoverable) adverse side-effects; but I'm fairly optimistic this will kill off the user-notification of an incomplete device-installation on my next boot. Time will tell... unless there's another update of Win10 before I have discovered the stability issues in my installation of the current version!
I followed your instructions, and got the same message that oldpaint got: "no changes or updates were necessary". Anything else that we can try?
I rebooted. Message no longer popped up in Action Center.


Occasion St-Hubert Toyota - Used Vehicles for sale - South Shore, St-Hubert, Chambly, Montreal, St-Jean.
Welcome to our used vehicles section . We always have a large selection of Toyota Corolla, Toyota RAV4, Toyota Camry, Toyota Matrix or Toyota Yaris from the years 2013, 2014, 2015, 2016 and 2017. Our Certified Toyota program ensures the delivery of a used Toyota car in a virtually new condition.


If it swims, we sell it!
At it's heart, The Fish Factory is a proud, family owned local company established in 1986. The goal is always to provide, not just advertise, the best healthy fish in a clean attractive environment. From marine & freshwater fish, to state of the art products, it's all here. Coupled with custom designed aquariums, and being the oldest maintenance firm in the area, we are your one stop shop. We want to you get excited about aquarium keeping.
Our focus is on direct importing 90% of our livestock. We use a unique disease treating program. All livestock must pass inspection before releasing to you. This takes our staff about 40 hours a week, just to maintain the quality you see at our location. Since 1986 we have shown pride in our shop, livestock and our excellence in customer service. We welcome you to a new experience in tropical fish keeping. We invite you to our beautiful, national award winning aquatic gallery of fish and supporting items to mentor you into the aquarium of your dreams.
When you arrive at The Fish Factory, you will instantly be greeted by 100's of clean underwater environments teaming with tropical fish from around the world. This provides you with design ideas of what you can do with your own aquarium design. As you continue your journey through, you will notice natural sections to inspire you to "go green". Using living corals, aquatic plants and supporting natural hardscape, you can let your imagination run free.
Let us assist you in working on your natural interior in a fun relaxed environment. Freshwater not your thing? No problem, continue your walk through to the living reef, a 2000 sq foot retreat dedicated to marine fish and corals. In this Caribbean themed showroom, your dreams begin. Many of our customers have described The Fish Factory as a tropical oasis graced with, beauty, warmth and style.


text:
Jared Leto flashes his abs on 50th birthday: 'How are you 50?'
Erin Donnelly
26 December 2021, 3:22 pm ·2 min read
Jared Leto is sharing shirtless shots on his 50th birthday. (Photo: REUTERS/Mario Anzuoni)
Jared Leto is flashing his abs at 50.
The Oscar winner turned the big 5-0 on Dec. 26, marking the occasion with not one but two shirtless shots. On Christmas, the eve of his birthday, the Santa-hat-wearing Suicide Squad star teased fans with a peek at his bare chest underneath a denim shirt.
A post shared by JARED LETO (@jaredleto)
For his actual big day on Sunday, the former My So-Called Life heartthrob ditched the shirt completely, posing topless and baring his sculpted — and seemingly oiled-up — abs while holding a slice of rainbow layer cake. It's unclear, however, when the photo was taken, as the bloodied lip and director's chair suggest Leto was captured behind-the-scenes while shooting Morbius, in which he plays a biochemist-turned-vampire.
"Thx for all the bday wishes!" Leto captioned the steamy post, which prompted a fan to respond, "How are you 50?"
According to Leto's Instagram, rock climbing helps him stay in shape. The star has also credited his mostly vegan diet.
Video: Jared Leto breaks down his iconic career
"I still have plenty of vices, but alcohol isn't one of them," he told British GQ in 2013. "It's probably just down to sleep and diet. If you travel long haul a lot or don't sleep much, it's not going to last very long, that's for sure. I'm pretty healthy so I think that helps a lot. I've been that way for a long time — 20 solid years of eating vegetarian/vegan and taking care of myself. That probably helps the preservation process."
Want lifestyle and wellness news delivered to your inbox? Sign up here for Yahoo Life's newsletter.
Elizabeth Hurley, 56, celebrates Christmas with hot pink minidress and a Liam Neeson cutout
Yahoo Life·1 min read
Adrienne Banfield-Norris celebrates 31 years of sobriety: 'I spent so many years in that insanity of active addiction, running in and out'
Demi Lovato shows off shaved head: '#FreshStart'


US investor Putnam Investments has bought a two per cent shareholding in Germany-headquartered eCommerce giant Zalando. At the beginning of October, Zalando announced a capital increase of four per cent – two per cent was bought by Canada-based Ontario Teachers' Pension Plan. The teachers' pension fund is also an investor in Rocket Internet's Latin America Zalando offshoot Dafiti.
Only now has the owner of the remaining two per cent been accounted for – US investor Putnam secured these shares for €72m.
Zalando's largest owner, Swedish bank AB Kinnevik, recently released its results for the first three quarters, valuing the eCommerce giant at €3.6bn – earlier this year it stood at €3.2bn. In the first half of 2013, Zalando produced €809m in revenue. It looks like these figures were enough to bring Zalando's two newest owners on board.
Launched in 2008, Zalando is now active in 14 European markets and broke even in its home DACH market last year. There's been speculation about an imminent IPO though, so far, the company's management team have remained mum on the subject.


Chantelle's blog: Ice Dance GOLD!
I was given this Sunshine Blog award, and I have to pass it on to 12 people.
They were also the youngest to ever win a gold medal in ice dance. They are 20 and 22 and ice dancers usually peak in their late 20's or early 30's!


text:
Tag Archives: Nepal
Written on October 10, 2013
"Reading: … " Book of the Year 2013 (Non-Fiction): Mike Searle — Colliding Continents: A Geological Exploration of the Himalaya, Karakoram, & Tibet
Mike Searle — Colliding Continents
Categories: Asia, Climbing, History, Reading, Science Tags: Afghanistan, England, Geo-Politics, Geography, Geology, Geophysics, India, Iran, K2, Mountaineering, Mountains, Nepal, Non-Fiction, Pakistan, Tibet
Written on June 11, 2013
Reading: Mike Searle — Colliding Continents: A geological exploration of the Himalaya, Karakoram, and Tibet
Here comes a deluge of serious reading. Well, another serious than the sci-fi I've been on of late (though with a new one from Charles Stross, and Iain Banks' – sadly sans-M – last one in the next weeks, I'm well-stocked for that flavour of serious), or perhaps gratuitously indulgent, after all, what could be more appealing that bloody massive upheavals of granite which can be either climbed or geologised, or in the case of Mike Searle's Colliding Continents, both at the same time?
This turned up in my feed from Oxford University Press' blog, and I decided to dispense with the actual reading of their post for the important act of ordering the book. Which arrived on Saturday, and which, obviously, I've devoured a third of already.
This is one of those very nice, medium-large hardcovers with barely a page empty of maps, illustrations, diagrams, or more importantly utterly gorgeous photographs of mountains. It's light on the technical side of geology, meaning someone with no prior knowledge of the subject would nonetheless not feel bewildered, yet equally there's a lot of terms even I, who used to slip into the Geology department and temporarily purloin monographs of the Karakoram had to pause to visualise what was actually meant. Lucky there's 30 pages of appendices covering all of this, and I think reading those first is probably a good idea.
Quite a bit of my interest in that region where Tibet becomes Central Asia becomes Indian subcontinent comes from geology. Also it comes from Deleuze and Guattari and reading of Steppe nomads, then looking at maps and trying to pin into that vast blankness between the Black Sea and the east coast of China names like Gobi, Taklamakan, Kashgar, Karakoram. Vast and blank indeed. So I set out to rectify my ignorance, becoming years – probably a lifetime as I've never been bored by this – of reading and reading and yes, still planning to go there.
A book like this is mainly a small moment of satisfying this love of mountains and this part of the world, and it does both superbly. Searle is one of those sensible geologists who realise early on it's the obvious career choice for someone who thinks suffering their way up glaciers and cliffs is most excellent fun, and whose love of both subjects only adds to his abilities in each.
The only thing that's missing for me is a map or maps of his annual-ish field trips. There are plenty of geological maps accompanying each chapter but either my map-reading skills have descended to bathic levels, I'm missing something fundamental, or there's a lack of correlation between those maps and the paths of the journeys he undertook. Perhaps unnecessary, but for me this would be an essential inclusion.
So, 464 pages of mountains! The cover pretty much sums it up; it's all just a lover's ode to the most beautiful upthrusting of granite in the world.
Categories: Asia, Climbing, History, Reading, Science Tags: Afghanistan, England, Geo-Politics, Geography, Geology, Geophysics, India, Iran, K2, Mountaineering, Mountains, Nepal, Pakistan, Tibet
Written on September 7, 2010
Reading: Matthew T. Kapstein – The Tibetans
Matthew T. Kapstein - The Tibetans
Categories: Asia, China 中国 中國, Culture, History, Politics, Reading, Words Tags: Afghanistan, Anthropology, Books, Central Asia, Nepal, Pakistan, Religion, Tibet, Xinjiang
shooting them like rats, dogs
A truly disgusting start to yesterday was reading about climbers in Tibet on Cho Oyu watching the Chinese Army massacre a group of Tibetan Refugees who were trying to cross Nangpa La into Nepal. China claims the soldiers, firing for 15 minutes on the starving refugees were acting in self defense. Do you still feel like going to the Beijing Olympics?
From International Campaign for Tibet, via China Digital Times 中国数字时代 is video from a Romanian cameraman. The video clearly depicts that the Tibetans had their backs to the soldiers, were unarmed, and offered no resistance.
China tries to gag climbers who saw Tibet killings – Leonard Doyle
From the Independent:
Chinese diplomats in the Nepalese capital of Kathmandu are tracking down and trying to silence hundreds of Western climbers and Sherpas who witnessed the killing of Tibetan refugees on the Nangpa La mountain pass last week.
This ominous development comes as fears grow for the safety of a group of Tibetan children, aged between six and 10, who were marched away after at least two refugees including a nun, were shot dead. [Full text]
Read a first person account from a Romanian climber who witnessed the killing. More information from climbers is available on Mounteverest.net, though some bloggers feel not enough climbers are coming forward to tell their story.
≈ For more on this story, see "Activist Group Says China Holding Tibetan Children" from VOA and a report from Phayul which includes eyewitness accounts of the incident. From VOA:
A Washington-based activist group says China is holding at least 10 children from a group of Tibetans who were fired on by Chinese security forces near the Tibetan border with Nepal last month.
In a statement issued Tuesday, the International Campaign for Tibet quotes a British mountain climber and several other witnesses who say they saw Chinese forces shoot at a group of about 70 Tibetans on Mount Cho Oyu September 30. The Tibetans are said to have been trying to flee into Nepal.
See also: This topic on the Web, via Google News.
This topic on the blogosphere, via Google Blog Search.
— China Digital Times 中国数字时代
body of the Tibetan nun, left in a snow path
Chinese officers with captured Tibetan children
Categories: Asia, China 中国 中國, Climbing, Politics Tags: Human Rights, Nangpa La, Nepal, Refugees, Tibet


Product prices and availability are accurate as of 2019-04-02 12:48:22 EDT and are subject to change. Any price and availability information displayed on http://www.amazon.com/ at the time of purchase will apply to the purchase of this product.
Hold down button until LED lights. Continue to hold. LED will go off. Continue to hold.
LED will flash once. Release button now for inching mode. Or continue to hold.
LED will flash twice. Release button now for self-locking mode. Or continue to hold.
LED will flash three times. Release button for interlock mode.
Hold down button until LED lights and release button while lit. LED will stay on. Press any key on remote. LED will flash twice confirming successful. Now press remote keys and relays will function as programmed. Inching= Single relay will stay on only as long as corresponding remote key is pressed.
Self-locking = Press corresponding key for on, press same key again for off, each relay independently.
Interlock = For each relay: press corresponding key for on (all others off).
Hold the button down (about 3 sec.) until the LED lights up, then push a button on the transmitter. You should see the LED flash rapidly to show that it is accepting the signal. Release the button and you are finish link transmitter with receiver.


THIS is the face that you will have to contend with, foul mama, if you so much as TRY to even THINK about hiding that last cookie from me. After a fine morning of muddy madness, I have earned every cookie and I count them. Oh yes, I count them. And you are one cookie short of the normal cookie allowance.


Massachusetts is a major center of business in the northeast, and 13 Fortune 500 companies call the state home, including General Electric, Liberty Mutual, and Staples. With one of the stronger economies in the country, the state is a highly desirable for CPAs. Jobs for accountants are expected to grow slower than average in the state, but Massachusetts pays CPAs an annual mean wage that's above the national average: around $80,280. Unsurprisingly, Massachusetts is home to offices for each of the "Big Four" international CPA firms (Deloitte & Touche, KPMG, PricewaterhouseCoopers, and Ernst & Young), all found in downtown Boston. The city is also the headquarters of major firms like Wolf & Co., Edelstein & Co., and Walter & Shuffain.
Search our comprehensive school directory to explore the accounting programs in Massachusetts, including campus-based, online and hybrid programs.
A 12% increase in employment opportunities for accountants and auditors in the state of Massachusetts is projected between 2012 and 2022, as compared to the average national growth rate of just over 13%. The top three potential employers include Wolf & Co., which grossed $31.49 million in revenue last year, Feeley & Driscoll which garnered $24.22 million and DiCicco, Gulman & Co. which earned $18.00 million in 2014.
Over the next seven years, approximately 41,590 accountants will be employed in Massachusetts, earning anywhere between $43,460 and $132,500 annually by working in accounting services. Wages are heavily dependent on licensure, speciality and degree level.
Aspiring CPAs in Massachusetts must sit for the Uniform CPA exam administered by NASBA and overseen by the Massachusetts State Board of Accountancy. Exam candidates must meet the eligibility requirements listed below in order to take the exam. The following list of schools ranked according to their CPA Exam pass rates below show a variety of colleges and universities in the state with top CPA Exam passing rates. Any CPA candidates who do not successfully pass all four sections of the exam within the designated 18 month period on their first try may apply to take the CPA Exam again, which is common for many accounting students.
Massachusetts offers an optional pre-evaluation service to help students determine if they meet the educational requirements before applying for the exam. This state does recognize CPA mobility legislation as well as obtaining a license by transfer.
Neither state resident status nor an ethics exam are required to obtain CPA licensure in the state of Massachusetts.
Students may substitute non-public accounting experience in order to meet the requirement for certification at the Board's discretion according to these special conditions.
Special Fees: A registration fee applies in addition to the application fee, and varies depending on the number of sections an individual is taking. The registration fee for all four sections is $177, for three sections is $157, for two is $137, for one is $117. A Certified Statement of Registration fee of $15 applies for each individual license.
The Massachusetts Board of Public Accountancy issues certificates and licenses, regulates and monitors CPAs and CPA firms' practices to ensure the quality of service provided to consumers, The Board also works with NASBA and AICPA by supervising the administration of CPA exams. Potential future CPAs and those already licensed may join the Massachusetts Society of CPAs which offers scholarships, a CPATrack, professional networking, a virtual community of peers and resources beneficial to those working or aspiring to work in the accounting field.


text:
Boechera tularensis, common name Tulare rockcress, is a plant species endemic to California. It has been reported from Inyo, Mono, Tulare, Fresno, Madera, El Dorado and Mariposa Counties. It grows on rocky slopes in subalpine habitats at elevations of 2400–3200 m.

Boechera tularensis is a biennial or short lived perennial herb, probably reproducing by apomixis (asexual production of cloned seeds). It can reach a height of up to 70 cm. Flowers are white to pale lavender with 6-7mm petals and bloom in June and July. Its fruit is appressed and 4–8.5 cm long. The plant is listed as "rare, threatened, or endangered in California and elsewhere" and is considered imperilled globally

Morphological evidence suggests that Boechera tularensis is an apomictic species that contains three different genomes, one each from B. rectissima, B. retrofracta, and B. stricta. It is most often confused with B. pinetorum and B. retrofracta, but can be distinguished. It is known from the southern Sierra Nevada (Fresno and Tulare counties).

References

tularensis
Flora of California
Plants described in 2007
Flora without expected TNC conservation status

redpajama_set_name: RedPajamaWikipedia


text:
Hyderabad: PJTSAU convocation to be held online
Hans News Service | 15 April 2021 8:08 PM GMT
PJTSAU convocation to be held online
Rajendranagar: The fifth convocation of Prof.Jayashankar Telangana State Agricultural University (PJTSAU) will be held virtually on April 17 at the uni...
Rajendranagar: The fifth convocation of Prof.Jayashankar Telangana State Agricultural University (PJTSAU) will be held virtually on April 17 at the university auditorium from 10.30 am onwards in the presence of Governor and Chancellor Dr Tamilisai Soundararajan.
Member of NITI Aayog, Prof Ramesh Chand, will deliver the convocation address. Dr V Praveen Rao, Vice-Chancellor, will present the university report. Members of the Board of Management and Academic council, graduates of the year and their parents, invited guests, faculty members, staff will participate in the online event.
A honoris causa degree will be conferred upon Prof Ramesh Chand, who is an eminent agricultural economist. Owing to Covid-19 pandemic, for the first time, the university is making arrangements to deliver the degree certificates online for 21 PhD, 148 MSc, one MTech and 517 UG students.
About 29 gold medals have been presented to the undergraduate and PG students for their extraordinary performance in academics.
PJTSAU
Tamilisai Soundararajan


text:
Honky Tonk Angels är ett studioalbum utgivet 1993 på skivbolaget Columbia Records av de framgångsrika countryartisterna Dolly Parton, Loretta Lynn och Tammy Wynette. Albumet producerades av Parton och Steve Buckingham. Det hade ryktats om ett projekt med dessa tre artister i mer än ett decennium, dock släpptes bara en singel, "Silver Threads and Golden Needles", som med nöd och näppe tog sig in på listorna.

Skivförsäljningen gav albumet placering 6 på Billboard:s countryalbumlista och placering 42 på Billboard 200, en blev Tammy Wynette näst högst rankade album på poplistorna och Loretta Lynns högsta på poplistan fram till hennes album Van Lear Rose 2005.

Albumet innehåller många så kallade standardmelodier inom countrymusiken, som "It Wasn't God Who Made Honky Tonk Angels" (där Kitty Wells gästsjunger), "Wings of a Dove" (en hitlåt 1960 för Ferlin Husky), "I Forgot More Than You'll Ever Know" (en hitlåt 1953 för The Davis Sisters (countrymusik), även känd som Skeeter Davis, och Betty Jack Davis), "Put it Off Until Tomorrow" (en hitlåt 1966 av Bill Phillips som blev Dolly Partons första framgång som låtskrivare), "Lovesick Blues" (en popstandard då den gjordes känd av Hank Williams', här sjunger trion till en inspelning av Patsy Cline), och "I Dreamed of a Hillbilly Heaven", Tex Ritters hitlåt från 1962 som här innehåller en ny taldialog.

De ursprungliga sångerna av Loretta Lynn och Tammy Wynette är solonummer, med körsång av Parton, medan "Sittin' on the Front Porch Swing" är ett solonummer av Dolly Parton. Albumet innehåller textblad skrivet av Ralph Emery.

Låtlista
It Wasn't God Who Made Honky Tonk Angels (J. D. "Jay" Miller) 2:51
Put It Off Until Tomorrow (Dolly Parton/Bill Owens) 2:38
Silver Threads and Golden Needles (Jack Rhodes/Dick Reynolds) 2:24
 Please Help Me I'm Falling (In Love with You)  (Don Robertson/Hal Blair) 2:35
"Sittin' on the Front Porch Swing" (Buddy Sheffield) 2:34
Wings of a Dove (Bob Ferguson) 2:54
I Forgot More Than You'll Ever Know (Cecil Null) 2:12
"Wouldn't It Be Great" (Loretta Lynn) 3:03
"That's the Way It Could Have Been" (Tammy Wynette) 2:55
"Let Her Fly" (Dolly Parton) 3:04
Lovesick Blues (Cliff Friend/Irving Mills) 2:18
I Dreamed of a Hillbilly Heaven (Hal Sothern/Eddie Dean) 3:32

Externa länkar
 "Honky Tonk Angels" på Dolly Parton On-Line

Källor

Album av Loretta Lynn
Album av Dolly Parton
Album av Tammy Wynette
Album utgivna på Columbia Records
Musikalbum 1993
Engelskspråkiga musikalbum


text:
EDITORIAL: Nuke subsidies need greater scrutiny
But a mostly secret, rubber-stamp BPU review seems inevitable
EDITORIAL: Nuke subsidies need greater scrutiny But a mostly secret, rubber-stamp BPU review seems inevitable Check out this story on mycentraljersey.com: https://www.mycentraljersey.com/story/opinion/editorials/2018/12/28/editorial-nuke-subsidies-need-greater-scrutiny/38809909/
Published 4:46 p.m. ET Dec. 28, 2018
New Jersey legislative committees approved bills that would let PSEG add a surcharge to help keep its South Jersey nuclear plants operational. File photo State legislative committees on Wednesday approved bills that would let PSEG add a surcharge on bills to help keep its South Jersey nuclear plants operational. Asbury Park Press file photo State lawmakers Wednesday approved bills that would allow PSEG to add a surcharge on bills to help keep its South Jersey plants operational.(Photo: ~File photo)
PSEG Nuclear has stepped up as the first – only? – company to apply for hundreds of millions of dollars in annual subsidies from ratepayers to keep its South Jersey plants sufficiently profitable.
We say "sufficiently," of course, because the issue at hand isn't whether the plants continue to make money. They do, a fact reinforced by an independent report estimating that the PSEG plants in Salem and Hope Creek will operate with a surplus through at least 2021. But this is about making enough money to be worth PSEG Nuclear's time and effort.
It was PSEG's threats of imminent closure and its own claims of financial need that established the subsidy parameters approved by lawmakers – up to $300 million a year. Legislative leaders accepted those claims at face value, with the caveat that the Board of Public Utilities would still have to review and approve any subsidy requests. That process will be carried out largely in private, however, and there's frankly little reason to expect BPU to serve as anything more than a rubber stamp.
The question now seems more to be how the subsidy pie will be divided. Will PSEG get the full $300 million it says it needs? Will the BPU trim that down a bit for show? Do other companies have a legitimate claim to some portion of those subsidies?
We have not objected to the prospect of some assistance for nuclear plants supposedly struggling to compete with abundant, cheaper natural gas. Nuclear energy is in one respect a "clean" energy alternative in that it generates no carbon emissions, and thus could play a valuable role in bridging to a future more reliant on renewable sources.
But lawmakers stacked the deck too heavily in PSEG's favor. Instead of evaluating needs in a transparent way in the earliest stages, supportive legislators instead fought hard for the $300 million pot that PSEG said it needed. As a result, they effectively accepted PSEG's numbers before a BPU review could even begin. That review now takes on more of a role of merely confirming the claims.
The energy landscape also continues to shift. As reports of the immediate and growing impact of climate change increase both in number and urgency, the bridge to renewable energy continues to shorten and grow more costly. Should New Jerseyans be asked to help keep nuclear plants operating when that process might help delay the energy transition we need to make? Also, should we consider nuclear energy to be "clean," as its proponents insist? It's true that an emissions-free source helps combat global warming, especially when replacing energy that might otherwise be produced by oil and gas. But nuclear plants also bring with them obvious and dramatic environmental risks.
The nuke subsidies die has already been cast. All we can ask for now is that the BPU take a sincere look at the numbers and determine what PSEG needs, not give the company what it wants. That could be a big difference that eases some of the burden on ratepayers.
Read or Share this story: https://www.mycentraljersey.com/story/opinion/editorials/2018/12/28/editorial-nuke-subsidies-need-greater-scrutiny/38809909/
Which picture of Somerset do you believe in?
New Jersey having problems? Not on this night. | Brescia
Opinion: Center of Excellence critical in Somerset County business future
Oct. 28, 2019, 5 a.m.


text:
Division d'Honneur este primul eșalon din sistemul competițional fotbalistic din Noua Caledonie. Se dispută sub forma unui turneu cu primele trei clasate din Division Honneur de Grande Terre și campioana din insule.

Echipele sezonului 2010
AS Kunié
AS Lössi
AS Magenta (Nouméa)
AS Mont-Dore
Gaïtcha FCN
Hienghène Sport
JS Baco
Mouli Sport

Foste campioane
1950: Impassible
1951: Impassible
1952: Indépendante
1953: Impassible
1954: Indépendante
1955: necunoscut
1956: Impassible
1957: PLGC
1958: PLGC
1959: PLGC
1960: Impassible
1961: necunoscut
1962: USC Nouméa
1963: USC Nouméa
1964-77: necunoscut
1978: Gélima Canala
1979-83: necunoscut
1984: AS Frégate
1985: AS Kunié
1986-92: necunoscut
1993: Wé Luécilla
1994: JS Baco
1995: JS Baco
1996: JS Traput
1997: JS Baco
1998: AS Poum
1999: Gaïtcha FCN
2000: JS Baco
2001: JS Baco
2002: AS Mont-Dore
2002-03: AS Magenta
2003-04: AS Magenta
2004-05: AS Magenta
2005-06: AS Mont-Dore
2006-07: JS Baco
2007-08: AS Magenta
2008-09: AS Magenta
2009: AS Magenta
2010:

Golgeteri

Legături externe
 Meciuri și rezultate pe fifa.com
 Lista campioanelor pe rsssf.com

Noua Caledonie


text:
Malva Castelli fue una actriz de teatro argentina.

Carrera
Damita joven de las cebezas de compañía de los años 1930, se lució en famosas compañías del momento donde brilló en el escenario al lado de figuras como Elsa O'Connor, Iris Marga, Carmen Casnell, Nicolás Fregues, Miguel Ligero, María Esther Paonessa, Laura Hernández, Pepita Muñoz, Anita Jordán, entre otros. Cemenzó su carrera en 1924 tras integrar la Compañía Nacional de los primeros actores Angelina Pagano y Francisco Ducasse

Integró entre 1932 y 1933 la "Compañía Dealessi-Camiña-Caplán-Serrano" conformada por la primera actriz Pierina Dealessi, Alfredo Camiña, Marcos Caplán y Enrique Serrano. En el elenco también se le sumaban Aparicio Podestá, María Armand, Martín Zabalúa, Gonzalo Palomero, Tomás Hartich, Arturo Podestá, Juan Castro, Cora Farías, Juan Viura, Tito Carné, entre otros. Con este grupo teatral estrena en teatros como el Smart o el Cómico, las obras La vuelta de Miss París, Detrás de cada puerta, Fiesta de Santa Angélica, Una santa en el infierno, entre otras.

En 1936 se destaca su labor al formar parte de la Compañía teatral Los Ases, con Olinda Bozán, Rosa Catá, Alberto Anchart (padre), Héctor Calcaño, Luisa Vehil, Paquita Vehil, Arturo Palito, Tito Lusiardo, José Otal, Delia Codebó y Leopoldo Simari.

A fines de la década del 30's y principio de los 40's forma parte de la compañía encabezada por Luis Arata.

Teatro
 1940: El señor maestro
 1939: La hermana Josefína
 1936: Sisebuta está loca
 1936: Noches de carnaval, estrenada en el Teatro Cómico.
 1933: Broadcasting
 1933: Se vende una negra.
 1932: La vuelta de Miss París.
 1932: Detrás de cada puerta.
 1932: Fiesta de Santa Angélica
 1932: Una santa en el infierno
 1924: La hermana terca

Referencias

Actrices de Argentina
Actrices de teatro de Argentina