LiveView has given us the ability to implement flexible and responsive UX almost entirely with server-side code. But what happens when our need for a responsive UI surpasses what LiveView seemingly offers? When the demands of a particular feature have us reaching for JavaScript? It is possible to incorporate custom JS into the LiveView life cycle with the help of a custom LiveView channel and a Registry. Keep reading to see how we did it!
The Problem
In a recent post, we built a straightforward chatting application backed by LiveView, PubSub and Presence. We implemented nearly all of the necessary features (live updates as users type in new messages, a list that keeps track of users in the chat room and who is typing!) with only 90 lines of LiveView code.
But then we ran into a blocker.
When new chat messages were appended to the chat window, they appeared just out of frame.
The chat window needed to scroll down to accommodate and display the new message. This is easy enough to do with just one or two lines of JavaScript: grab the height of the chat window, and set the scrollTop
accordingly.
If you’re familiar with Phoenix Channels, you might reach for something like this:
channel.on("new_message", (msg) => {
const targetNode = document.getElementsByClassName("messages")[0]
targetNode.scrollTop = targetNode.scrollHeight
})
But wait! The LiveView client-side library only responds to one event from the LiveView process running on the server––the diff event. This event isn’t granular enough to tell us what changed on the page. It merely forces the appropriate portions of the page to re-render.
So, how can we get our LiveView to emit an event that our front-end can respond to in order to fire our scrollTop
-adjusting JS?
The Solution
We need to do a few things in order to get this working:
- Extend the LiveView socket with a custom channel
- Teach our LiveView processes to send messages to that channel, so that the channel can push them to the client.
It’s worth noting here that the responsibility of a custom LiveView channel should be narrowly scoped. LiveView can and should handle almost all of the updates to the LiveView template. That’s the beauty of LiveView! We don’t need to write a set of custom client-side functions for updating the page based on specific events like we’ve become used to doing when working with Phoenix Channels. However, when we need to trigger a client-side interaction, like our scrollTop
adjustment, that the LiveView client isn’t capable of handling, we can reach for a custom channel.
Now that we have a basic understanding of the problem we’re trying to solve, and the tools we’ll use to solve it, let’s get started!
The Process
Before we start writing code, let’s walk through the desired code flow of this feature, one step at a time.
- User visits
/chats/:id
- Controller mounts the live view and renders the static template
- Client connects to the Live View socket and joins a custom channel on this same socket
Later…
- User submits new chat message, sending an event to the live view
- The live view responds to the message by updating state, re-rendering the page and broadcasting the event to the other live view processes subscribing to that chat room topic
- The other live views receive the broadcast, update their own state and re-render the template
- The live views send the message to their “associated” channel (i.e. the channel joined on the live view’s socket)
- The channel receives the message and pushes it out to the front-end
- Front-end receives the message and responds by triggering our
scrollTop
adjustment JavaScript
There is a lot of code to get through, so we’ve organized our approach into the following parts:
I. Establishing the Socket and Channel
II. Handling Events in the LiveView
III. Communicating from the LiveView to the Channel
IV. Sending Messages From the Channel to the Front-End
Getting Started
If you’d like to follow along with this tutorial, we recommend reading and completing the tutorial in our previous post here first. This will get your code into the correct starting state. You can also clone down the repo here to get the starting code. Otherwise, you can checkout the completed code here.
Part I: Establishing the Socket and Channel
In order to guarantee that the live view process can send a message to the right channel at the right time, we need to have the live view share a socket with that channel. Let’s start by focusing on this portion of the code flow:
- User visits
/chats/:id
- Controller mounts the live view and renders the static template
- Client connects to the Live View socket and joins the channel on this same socket
Here’s a closer look at how this procedure works:
Let’s dive in and write some code!
Extending the LiveView Socket
In order to define a custom channel that will share a socket with our LiveView process, we need to extend the LiveView socket that the LiveView library provides us. LiveView doesn’t (yet) provide a way for us to extend this module programmatically, so we’ll define our own socket with everything it needs to support our LiveView and our custom channel:
# lib/phat_web/channels/live_socket.ex
defmodule PhatWeb.LiveSocket do
@moduledoc """
The LiveView socket for Phoenix Endpoints.
"""
use Phoenix.Socket
defstruct id: nil,
endpoint: nil,
parent_pid: nil,
assigns: %{},
changed: %{},
fingerprints: {nil, %{}},
private: %{},
stopped: nil,
connected?: false
channel "lv:*", Phoenix.LiveView.Channel
channel "event_bus:*", PhatWeb.ChatChannel
@doc """
Connects the Phoenix.Socket for a LiveView client.
"""
@impl Phoenix.Socket
def connect(_params, socket, _connect_info) do
{:ok, socket}
end
@doc """
Identifies the Phoenix.Socket for a LiveView client.
"""
@impl Phoenix.Socket
def id(_socket), do: nil
end
The only line we need to add in addition to what we’ve copied from the LiveView source code is the channel definition in which we map the topic, "event_bus:*"
to our soon-to-be-defined custom channel.
channel "event_bus:*", PhatWeb.ChatChannel
Next we’ll tell our app’s Endpoint
module to map the socket mounted at the "/live"
endpoint to the socket we just defined:
# lib/phat_web/endpoint.ex
defmodule PhatWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :phat
# socket "/live", Phoenix.LiveView.Socket
socket "/live", PhatWeb.LiveSocket
...
end
Defining the Custom Channel
Now we’re ready to define our ChatChannel
:
# lib/phat_web/channels/chat_channel.ex
defmodule PhatWeb.ChatChannel do
use Phoenix.Channel
def join("event_bus:" <> _chat_id, _message, socket) do
{:ok, socket}
end
end
Connecting to the Socket and Joining the Channel
With our socket and our channel defined, we can tell the front-end client to join the channel after connecting to the LiveView socket:
// assets/js/app.js
import LiveSocket from "phoenix_live_view"
let chatId = window.location.pathname.split("/")[2] // just a hack to get the chatId from the route, there are definitely better ways to do this!
const liveSocket = new LiveSocket("/live")
liveSocket.connect()
let channel = liveSocket.channel("event_bus:" + chatId, {})
Now, when the page loads, we will:
- Connect to and start the LiveView process running over the socket
- Join a channel over that same socket
Later, we can write some code on the front-end to respond to a specific event by changing the chat box’s scroll height:
channel.on("new_message", (msg) => {
targetNode = document.getElementsByClassName("messages")[0]
targetNode.scrollTop = targetNode.scrollHeight
})
So, how can we get our channel to send the "new_message"
event to the front-end? Let’s find out!
Part II: Handling Events in the LiveView
In this section, we’ll dive into the following portion of the process:
- User submits a new chat message, sending an event to the live view; The live view updates its state and re-renders the template
- The live view broadcasts the event to the other live view processes subscribing to that chat room topic which then update their own state and re-render their templates
- The live views send a message to themselves, instructing them to in turn send a message to their “associated” channel (i.e. the channel joined on the live view’s socket). This ensures that the live view will finish re-rendering before telling the channel to push a message to the front-end.
Here’s a closer look at this flow:
Receiving Events in the LiveView
When a user submits a new message via the chat form, it will send the "new_message"
event to the LiveView process, over the socket. Our live view process already responds to this message by:
- Updating its own state and re-rendering the template to display the new message.
- Broadcasting the message to the other running live view processes subscribed to the same topic so that everyone gets the new message and subsequent re-render.
To get a refresher on how this works, check out our earlier post here. In this post, we’ll just take a brief look at that code:
# lib/phat_web/live/chat_live_view.ex
# this function fires when we receive the "new_message" event from the front-end
def handle_event("new_message", %{"message" => message_params}, socket) do
chat = Chats.create_message(message_params)
PhatWeb.Endpoint.broadcast(topic(chat.id), "new_message", %{chat: chat})
{:noreply, assign(socket, chat: chat, message: Chats.change_message())}
end
# this function fires when all of the subscribing live view processes receive the broadcast from above
def handle_info(%{event: "new_message", payload: state}, socket) do
{:noreply, assign(socket, state)}
end
Its important to note that the live view is broadcasting the message to all of the LiveView processes subscribed to the chat room’s topic, including itself. However, LiveView is smart enough not to re-render a page for which there are no diffs, so this isn’t an expensive operation.
Sending Messages from the LiveView to the Channel
We need to ensure that the page has a chance to re-render before we have the channel send the message to the front-end. Otherwise the JavaScript function to adjust scrollTop
might run before the new message is present on the page, thereby failing to actually make an adjustment to the chat window.
After this handle_info/2
function returns is the point at which we can be sure all LiveView templates are re-rendered:
def handle_info(%{event: "new_message", payload: state}, socket) do
{:noreply, assign(socket, state)}
end
So, how can we make sure each LiveView process handling this message will only send a message to the channel after this function finishes working? We can use send/2
to have the live view send a message to itself! Since a process can only do one thing at a time, the live view process will finish the the current work in the handle_info/2
processing the "new_message"
event before acting on the message it receives from itself.
def handle_info(%{event: "new_message", payload: state}, socket) do
send(self(), {:send_to_event_bus, "new_message"})
{:noreply, assign(socket, state)}
end
def handle_info({:send_to_event_bus, msg}, socket) do
# send a message to the channel here!
{:noreply, socket}
end
Now we’ve captured the moment in time at which to send a message from the LiveView process to the Channel process. But wait! How can we send a message to a process whose PID we don’t know? The LiveView process, in its current form, doesn’t know about the channel process with which it shares a socket. In order to fix this, we’ll need to leverage a Registry.
Part III: Communicating from the LiveView to the Channel
In this section, we’ll register our channel process so that the live view can look up and send a message to the appropriate channel PID. Then, we’ll teach the live view how to perform this lookup and send a message to the right channel PID.
Here’s the code flow we’re aiming for:
- The LiveView is mounted from the controller and stores a unique identifier of a “session UUID” in its own state; it renders the template with a hidden element that contains the session UUID encoded in a
Phoenix.Token
- The channel’s socket is connected with this token; the socket stores it in state.
- The channel is joined; it takes the session UUID from its socket’s state and registers its PID under a key of that UUID.
Later…
- When the user submits a new chat message, the LiveView processes that received the message broadcast will look up the channel PID under the session UUID in the registry
- Each live view will then send the message to the PID they looked up
Defining the Channel Registry
We’ll use a process registry, implemented with Elixir’s native Registry module, to keep track of the channel PID so that the LiveView can look up its associated channel in order to send it a message.
Its important to note that Elixir’s Registry module isn’t distribution friendly––if you look up a given PID created on one server on a totally different server, there’s no guarantee that it will refer to the same process. But! Since our channel shares a socket with the LiveView process, it is guaranteed that the live view and the channel are running on the same server.
We’ll tell Elixir’s Registry supervisor to start supervising a named registry called SessionRegistry
when our app starts up:
# application.ex
def start(_type, _args) do
children = [
Phat.Repo,
PhatWeb.Endpoint,
PhatWeb.Presence,
{Registry, [keys: :unique, name: Registry.SessionRegistry]}
]
opts = [strategy: :one_for_one, name: Phat.Supervisor]
Supervisor.start_link(children, opts)
end
We want to register our channel PID when the channel is joined. But we need to store the PID under a unique key that the live view can use to look it up by later. So, we need to create such an identifier and find a way to make it available to both the live view and the channel.
Sharing the Session UUID
When the LiveView first mounts via the controller, we’ll create a unique identifier––a session UUID––to store in the live view’s state:
# lib/phat_web/controllers/chat_controller.ex
def show(conn, %{"id" => chat_id}) do
chat = Chats.get_chat(chat_id)
session_uuid = Ecto.UUID.generate()
LiveView.Controller.live_render(
conn,
ChatLiveView,
session: %{
chat: chat,
current_user: conn.assigns.current_user,
session_uuid: session_uuid
}
)
end
# lib/phat_web/live/chat_live_view.ex
def mount(%{chat: chat, current_user: current_user, session_uuid: session_uuid}, socket) do
...
{:ok, assign(socket,
chat: chat,
message: Chats.change_message(),
current_user: current_user,
users: Presence.list_presences(topic(chat.id)),
username_colors: username_colors(chat),
session_uuid: session_uuid,
token: Phoenix.Token.sign(PhatWeb.Endpoint, "user salt", session_uuid)
)}
end
In the mount/2
function of our live view, we store the session UUID in the socket’s state so that we can use it to look up the channel PID later. We also encode the session UUID into a signed Phoenix.Token
so that we can put it on the page and use it when we join the channel from the client-side.
# lib/phat_web/templates/chat/show.html.leex
<%= tag :meta, name: "channel_token", content: @token %>
Let’s take a look at how we will give our channel access to this token.
When we send the socket connection request from the browser, we hit the connect/3
function of our extended Live View socket, PhatWeb.LiveSocket
. At this time, we don’t have access to the Live View process’s representation of the socket, but we do have access to the channel’s representation of the socket.
We need to give the channel awareness of the session UUID. So, we’ll include the signed token from the page in the socket connection request and use connect/3
to store the session UUID in the channel’s socket state.
We’ll include the token in our socket connection request on the front-end:
// assets/js/app.js
const channelToken = document.getElementsByTagName('meta')[3].content
const liveSocket = new LiveSocket("/live", {params: {channel_token: channelToken}})
liveSocket.connect()
And we’ll have the PhatWeb.LiveSocket.connect/3
function verify the token, extract the session UUID and store it in the channel socket’s state:
# lib/phat_web/channels/live_socket.ex
def connect(params, socket, _connect_info) do
case Phoenix.Token.verify(socket, "user salt", params["channel_token"], max_age: 86400) do
{:ok, session_uuid} ->
socket = assign(socket, :session_uuid, session_uuid)
{:ok, socket}
{:error, _} ->
:error
end
end
Registering The Channel Process
Now, when we join the channel, we can look up the :session_uuid
in the channel socket’s state and use it to register the channel’s PID in the SessionRegistry
under a key of this UUID:
# lib/phat_web/channels/chat_channel.ex
defmodule PhatWeb.ChatChannel do
use Phoenix.Channel
def join("event_bus:" <> _chat_id, _message, socket) do
Registry.register(Registry.SessionRegistry, socket.assigns.session_uuid, self())
{:ok, socket}
end
end
Now our registry is up and running, and we’re registering a given channel PID under a unique identifier (session UUID) that live view with which the channel shares a socket connection is aware of.
We’re ready to have the live view send a message to its channel!
Sending Messages to the Channel
Let’s recap the “new chat message” process so far:
- A user submits the “new message” form and sends a
"new_message"
event to the live view - The live view responds to this event by updating its own socket’s state, re-rendering and broadcasting the
"new_message"
event to all the live view processes subscribing to the topic for this chat room, i.e. the processes that represent the other users in the chat room. - The live view processes receive this message broadcast and respond to it by updating their own state and re-rendering. They also
send
a message to themselves that they will process once they finish re-rendering. - The live view processes responds to the message they sent themselves, telling themselves to send a message to the channel with which they share a socket.
Now our live views have what they need to look up their associated channel. They are storing the same session UUID in state that the channel used to register its PID in the SessionRegistry
. So, our live views can look up the channel PID and send a message to that PID.
# lib/phat_web/live/chat_live_view.ex
# handle the broadcast of the "new_message" event from the live view that received it from the user
def handle_info(%{event: "new_message", payload: state}, socket) do
send(self(), {:send_to_event_bus, "new_message"})
{:noreply, assign(socket, state)}
end
# handle the message sent above, after re-rendering the template
def handle_info({:send_to_event_bus, msg}, socket = %{assigns: %{session_uuid: session_uuid}}) do
[{_pid, channel_pid}] = Registry.lookup(Registry.SessionRegistry, session_uuid)
send(channel_pid, msg)
{:noreply, socket}
end
Each live view process shares a session UUID with the channel that was joined on its socket. In this sense, each live view has an “associated” channel. By registering the channel PID under this session UUID, the given live view can look up its associated channel’s PID and send a message to that channel and that channel only.
Next up, we need to teach our channel to respond to this message.
Part IV: Sending Messages from the Channel to the Front End
In this section, we’ll focus on the following portion of our process:
- The channel receives the message from the live view and pushes it out to the front-end
- The front-end receives the message and responds by triggering our
scrollTop
adjustment JavaScript
Here’s a closer look:
Receiving Messages in the Channel
We need to define a handle_info/
in the ChatChannel
that knows how to respond to "new_message"
messages by pushing them down the socket to the front-end.
# channel
def handle_info("new_message", socket) do
push(socket, msg, %{})
{:noreply, socket}
end
Responding to Messages on the Front-End
On the front-end, our channel JS is ready and waiting to fire:
// assets/js/app.js
channel.on("new_message", function() {
const targetNode = document.getElementsByClassName("messages")[0]
targetNode.scrollTop = targetNode.scrollHeight
})
Now, right after the page re-renders, the channel will receive the "new_message"
message and push it to the client which is listening for just this event. The client reacts by firing our scrollTop
adjustment JS and the user experiences a responsive UI––a chat window that automatically and seamlessly scrolls down to accommodate new messages in real-time.
Conclusion
We’ve seen that a seeming “limit” of LiveView can be surpassed by incorporating available Phoenix real-time tools––in this case Phoenix Channels. The work in this post raises the question: “What should LiveView be capable of?” Is the extension of LiveView with a custom Phoenix Channel a violation of the “purpose” of LiveView? Does such a use-case mean we should eschew LiveView in favor of Channels?
I think there are still distinctive advantages to using LiveView to back a feature like our chat app. Almost all of the chat functionality is handled in less than 100 lines of LiveView code. This is as opposed to all of the Channel back and front-end code that you would otherwise write. So, I would like to see LiveView become more extensible and configurable, making it easier to incorporate custom channels out-of-the-box.
Caught a mistake or want to contribute to the article? Edit this page on GitHub!


|
Slow Transients Pipeline Prototype
Component of the Science Data Processor being developed in the context of the Square Kilometre Array international project, which provides fast snapshot imaging, object detection and cataloguing for the identification of astrophysical image-plane transients.
|
Function prototypes of the connected component labeling. More...
#include "../global_macros.h"
#include "../types.h"
#include "matstp.h"
#include <armadillo>
#include <cassert>
#include <tbb/tbb.h>
Go to the source code of this file.
Classes | |
| struct | stp::LabelDataThread |
| LabelDataThread struct is used to store start column and detected label information of a thread. More... | |
Namespaces | |
| stp | |
Functions | |
| template<bool findNegative = false> | |
| std::tuple< MatStp< int >, MatStp< uint >, uint, uint > | stp::labeling_8con (const arma::Mat< real_t > &I, const real_t analysis_thresh_pos, const real_t analysis_thresh_neg) |
| Performs the connected components labeling (CCL) algorithm assuming 8-connectivity. More... | |
| template<bool findNegative> | |
| std::tuple< MatStp< int >, MatStp< uint >, uint, uint > | stp::labeling_4con (const arma::Mat< real_t > &I, const real_t analysis_thresh_pos, const real_t analysis_thresh_neg) |
| Performs the connected components labeling (CCL) algorithm assuming 4-connectivity. More... | |
Function prototypes of the connected component labeling.


Instructions:
Click the "New Puzzle" button to generate a puzzle and start the timer.
Click an empty square to enter the appropriate number.
Click the "Check All" button to check your answers when finished.
You can also check or reveal an individual square with those buttons,
or check all squares while solving.
Status messages are displayed in the box at the bottom of the page.
Status:


I'm sorry but my site doesn't work properly without JavaScript enabled. Please enable it to continue.


Steem Developer Portal
JS: Grant Active Permission
How to grant and revoke active permission to another user.
Full, runnable src of Grant Active Permission can be downloaded as part of the JS tutorials repository.
This tutorial will take you through the process of checking a specific users’ data, altering the array pertaining to the active account_auths
, and then broadcasting the changes to the blockchain. Demo account information has been provided to assist with the tutorial. This tutorial has been set up for the testnet
but can be easily be changed for production
.
Providing another user active permission for your account enables them to do fund transfers from your account. This can be usefull in setting up a secondary account(s) to manage funds for a main account or having a backup should you lose passwords for the main account.
One of the common practice nowadays is to lend/delegate SP to another account, above same technique can be used to create market around it with minimum 3rd party trust. All your funds stay in your account. You can use/create automated system where you can lease for certain period of time and system can take care of payments and release of delegations (notify clients). Even better, you can use multi-signature feature to establish 100% trust where clients will have to confirm, approve transactions.
 It is really not easy to hack Steem accounts, let alone take control over it. But without careful use (revealing private keys) loosing liquid funds are not that difficult and it takes only couple seconds to do that, keeping most value powered up always helps.
this article has more detail around active authorities
Intro
This tutorial uses the database API
to gather account information for the user that is granting active permission to a secondary user. This information is used to check current permissions as well as to build the broadcast
operation. Granting or revoking active permission works by changing the array of usernames containing this information and then pushing those changes to the blockchain. The parameters for this updateAccount
function are:
- account - The username of the main account
- active - Optional parameter to denote changes to the active authority type. This is the parameter that we will be changing in this tutorial
- jsonMetadata - This is a string value obtained from the current account info
- memoKey - This is the public memoKey of the user
- owner - Optional parameter to denote changes to the owner authority type
- posting - Optional parameter to denote changes to the posting authority type
- privateKey - The private
active
key of the user
The only other information required is the username of the account that the active permission is being granted to.
The tutorial is set up with three individual functions for each of the required operations - checking permission status, granting permission and revoking permission.
Steps
- Configure connection Configuration of
dsteem
to communicate with a Steem blockchain - Input variables Collecting the required inputs via an HTML UI.
- Database query Sending a query to the blockchain for the active permissions (status)
- Object creation Create the array and subsequent data object for the broadcast operation
- Broadcast operation Broadcasting the changes to the blockchain
1. Configure connection
As usual, we have a public/app.js
file which holds the Javascript segment of the tutorial. In the first few lines we define the configured library and packages:
import { Client, PrivateKey } from 'dsteem';
import { Testnet as NetConfig } from '../../configuration'; //A Steem Testnet. Replace 'Testnet' with 'Mainnet' to connect to the main Steem blockchain.
let opts = { ...NetConfig.net };
//connect to a steem node, testnet in this case
const client = new Client(NetConfig.url, opts);
Above, we have dsteem
pointing to the testnet with the proper chainId, addressPrefix, and endpoint by importing it from the configuration.js
file. Due to this tutorial altering the blockchain it is preferable to not work on production.
2. Input variables
The required parameters for the account status query is recorded via an HTML UI that can be found in the public/index.html
file. Any active account information can be used for this tutorial but to make things easier we populate these fields once the UI loads.
window.onload = async () => {
const account = NetConfig.accounts[0];
const accountI = NetConfig.accounts[1];
document.getElementById('username').value = account.address;
document.getElementById('privateKey').value = account.privActive;
document.getElementById('newAccount').value = accountI.address;
};
All of the functions use the same input variables. Once the function is activated via the UI the variables are allocated as seen below.
//get username
const username = document.getElementById('username').value;
//get private active key
const privateKey = PrivateKey.fromString(
document.getElementById('privateKey').value
);
//get account to provide active auth
const newAccount = document.getElementById('newAccount').value;
3. Database query
The queries are sent through to the steem blockchain with the database API
using the getAccounts
function. The results of the query is used to check the status of the current active authorisations and parameters as per the intro
.
//query database for active array
var _data = new Array
_data = await client.database.getAccounts([username]);
const activeAuth = _data[0].active;
//check for username duplication
const checkAuth = _data[0].active.account_auths;
var arrayindex = -1;
var checktext = " does not yet have active permission"
for (var i = 0,len = checkAuth.length; i<len; i++) {
if (checkAuth[i][0]==newAccount) {
arrayindex = i
var checktext = " already has active permission"
}
}
The result of this status query is then displayed on the UI along with the array on the console as a check.
document.getElementById('permCheckContainer').style.display = 'flex';
document.getElementById('permCheck').className = 'form-control-plaintext alert alert-success';
document.getElementById('permCheck').innerHTML = newAccount + checktext;
console.log(checkAuth);
4. Object creation
The database query is the same for all the functions and is required to create an updated array to broadcast to the blockchain. This is how we determine whether a user permission will be added or revoked. The actual operation is the same apart from the array variable as can be seen below. The difference is in that when creating a permission, an element is added to the account_auths
array where revoking removes an element from it.
//add account permission
activeAuth.account_auths.push([
newAccount,
parseInt(activeAuth.weight_threshold)
]);
activeAuth.account_auths.sort();
//revoke permission
activeAuth.account_auths.splice(arrayindex, 1);
When adding to the array (creaing permission) it is required to sort the array before we can broadcast. The Steem blockchain does not accept the new fields in the array if it’s not alphabetically sorted. After the active array has been defined, the broadcast object can be created. This holds all the required information for a successful transaction to be sent to the blockchain. Where there is no change in the authority types, the parameter can be omitted or in the case of required parameters, allocated directly from the database query.
//object creation
const accObj = {
account: username,
json_metadata: _data[0].json_metadata,
memo_key: _data[0].memo_key,
active: activeAuth,
}
5. Broadcast operation
With all the parameters assigned, the transaction can be broadcast to the blockchain. As stated before, the actual broadcast
operation for both new permissions and to revoke permissions use the same parameters.
//account update broadcast
client.broadcast.updateAccount(accObj, privateKey).then(
function(result) {
console.log(
'included in block: ' + result.block_num,
'expired: ' + result.expired
);
document.getElementById('permCheckContainer').style.display = 'flex';
document.getElementById('permCheck').className = 'form-control-plaintext alert alert-success';
document.getElementById('permCheck').innerHTML = "permission has been revoked for " + newAccount;
},
function(error) {
console.error(error);
document.getElementById('permCheckContainer').style.display = 'flex';
document.getElementById('permCheck').className = 'form-control-plaintext alert alert-danger';
document.getElementById('permCheck').innerHTML = error.jse_shortmsg;
}
);
The results of the operation is displayed on the UI along with a block number in the console to confirm a successful operation. If you add permission to an account that already has permission, or if your private key has been entered incorrectly, an error of “Missing Active Authority” will be displayed.
Steemconnect offers an alternative to revoking active permission with a “simple link” solution. Instead of running through a list of operations on your account, you can simply use a link similar to the one below. You will be prompted to enter your usename and password and the specified user will have their permissions removed instantly. https://v2.steemconnect.com/revoke/@username This is similar to the steemconnect links that have been covered in previous tutorials. For a list of signing operations that work in this manner you can go to https://v2.steemconnect.com/sign
To run this tutorial
- clone this repo
cd tutorials/31_grant_active_permission
npm i
npm run dev-server
ornpm run start
- After a few moments, the server should be running at http://localhost:3000/


From school to your office, Skrifa is the word processor for everyone. With a minimal, distraction free, simple and yet powerful interface, it's focused on what you really care, your content. It is so versatile that you'll have no problem using it for any scenario, as a power user or just as a simple quick note taking app. From text styling to videos and images, Skrifa provides the right set of tools you need to take awesome notes.
We all have different needs, so why not have an specific app that matches what we really want? That's why Skrifa comes in many flavors!
The vanilla Skrifa, is all about keeping your privacy safe. With encryption to all of your notes by default using PGP, secure sharing of your notes and other PGP functionalities, this is the best note taking app for you and your privacy.
If you are not someone who is interested in protecting your privacy, the Skrifa Lite app is just for you, with all the features of the vanilla app and stripping down the encryption, Skrifa Lite is blazing fast.
All your notes are encrypted by default using PGP keys, you can also import an existing key and share your notes securely!
All your notes are stored locally so you'll always be able to work without the need of a network connection.
Writing math on your computer? With the built-in MathJax support, you'll be able to write it in a simple manner and with beautiful results.
Wouldn't it be wonderful if you could take notes of code and it was highlighted? Wait no more, adding code snippets to your notes is just a click away!
An image says more than one thousand words, importing images and embedding videos to your notes is plain simple just like it should be.
We all already have notes in many formats, Markdown, Word documents, plain text files, why not just import them and have them all right in the same place?
Not only importing your previous notes is important, you can also export your notes as Markdown, HTML, PDF and Skrifa files.
We all have notes for different things, from school subjects to real life work and Skrifa makes it easy to keep all your notes right where they belong, grouping them in notebooks makes it easier for you to find your notes.
Skrifa only saves your notes locally, therefore it's your responsibility to keep a backup in order to recover from any disaster. Skrifa makes creating and restoring from a backup something just a click away.
Design is such a matter of perspectives that it's impossible to match everyone taste but thanks to the Custom Themes, you can make Skrifa look just the way you'd love it to!
Released under the GPLv3 License, you can review and contribute to the code of all the apps and this website on GitHub.
You can either choose to buy or download Skrifa for free, there is NO difference in the product you'll get however do keep in mind that buying it will contribute to its development and every gain will be split 50/50 between the projects skrifa uses internally to work and project contributors according to their contribution.
You can also support Skrifa's Development through Patreon
We've all heard that phrase that says "If you are not paying it, you are the product", Skrifa is a Free Open Source Software, it does not show ads, it does not track you, it will never upload your info anywhere (except that of an Skrifa account) Skrifa is here to make you regain safety and privacy so you don't have to worry about this.
You'll be shown an icon every time a new update is ready for you, to update your Skrifa you'll have to download the update and install it, in the case of windows just run the new installer, on macOS replace the Skrifa app with the new one, on Linux install your new version or if you installed it via a package manager, the update will get to you automatically.
By encrypting all your notes, you are the only one who will be able to decrypt them, however Skrifa can't protect you if your computer has been compromised (keyloggers, trojans etc.)
You can export your notes in an encrypted or unencrypted format, if you export them unencrypted then anyone will be able to read that exported file.


STRTOUL
Section: Linux Programmer's Manual (3)
Updated: 2014-03-18
Index
Return to Main Contents
NAME
strtoul, strtoull, strtouq - convert a string to an unsigned long integer
SYNOPSIS
#include <stdlib.h>
unsigned long int strtoul(const char *nptr, char **endptr, int base);
unsigned long long int strtoull(const char *nptr, char **endptr,
int base);
Feature Test Macro Requirements for glibc (see
feature_test_macros(7)):
strtoull():
-
_XOPEN_SOURCE >= 600 || _BSD_SOURCE || _SVID_SOURCE || _ISOC99_SOURCE ||
_POSIX_C_SOURCE >= 200112L;
or
cc -std=c99
DESCRIPTION
The
strtoul()
function converts the initial part of the string
in
nptr
to an
unsigned long int
value according to the
given
base,
which must be between 2 and 36 inclusive, or be
the special value 0.
The string may begin with an arbitrary amount of white space (as
determined by
isspace(3))
followed by a single optional '+' or '-'
sign.
If
base
is zero or 16, the string may then include a
"0x" prefix, and the number will be read in base 16; otherwise, a
zero
base
is taken as 10 (decimal) unless the next character
is '0', in which case it is taken as 8 (octal).
The remainder of the string is converted to an
unsigned long int
value in the obvious manner,
stopping at the first character which is not a
valid digit in the given base.
(In bases above 10, the letter 'A' in
either uppercase or lowercase represents 10, 'B' represents 11, and so
forth, with 'Z' representing 35.)
If
endptr
is not NULL,
strtoul()
stores the address of the
first invalid character in
*endptr.
If there were no digits at
all,
strtoul()
stores the original value of
nptr
in
*endptr
(and returns 0).
In particular, if
*nptr
is not '\0' but
**endptr
is '\0' on return, the entire string is valid.
The
strtoull()
function works just like the
strtoul()
function but returns an
unsigned long long int
value.
RETURN VALUE
The
strtoul()
function returns either the result of the conversion
or, if there was a leading minus sign, the negation of the result of the
conversion represented as an unsigned value,
unless the original (nonnegated) value would overflow; in
the latter case,
strtoul()
returns
ULONG_MAX
and sets
errno
to
ERANGE.
Precisely the same holds for
strtoull()
(with
ULLONG_MAX
instead of
ULONG_MAX).
ERRORS
- EINVAL
-
(not in C99)
The given
base
contains an unsupported value.
- ERANGE
-
The resulting value was out of range.
The implementation may also set
errno
to
EINVAL
in case
no conversion was performed (no digits seen, and 0 returned).
ATTRIBUTES
Multithreading (see pthreads(7))
The
strtoul(),
strtoull(),
and
strtouq()
functions are thread-safe with exceptions.
These functions can be safely used in multithreaded applications,
as long as
setlocale(3)
is not called to change the locale during their execution.
CONFORMING TO
strtoul()
conforms to SVr4, C89, C99, and POSIX-2001, and
strtoull()
to C99 and POSIX.1-2001.
NOTES
Since
strtoul()
can legitimately return 0 or
ULONG_MAX
(ULLONG_MAX
for
strtoull())
on both success and failure, the calling program should set
errno
to 0 before the call,
and then determine if an error occurred by checking whether
errno
has a nonzero value after the call.
In locales other than the "C" locale, other strings may be accepted.
(For example, the thousands separator of the current locale may be
supported.)
BSD also has
u_quad_t strtouq(const char *nptr, char **endptr, int base);
with completely analogous definition.
Depending on the wordsize of the current architecture, this
may be equivalent to
strtoull()
or to
strtoul().
Negative values are considered valid input and are
silently converted to the equivalent
unsigned long int
value.
EXAMPLE
See the example on the
strtol(3)
manual page;
the use of the functions described in this manual page is similar.
SEE ALSO
atof(3),
atoi(3),
atol(3),
strtod(3),
strtol(3)
Index
- NAME
-
- SYNOPSIS
-
- DESCRIPTION
-
- RETURN VALUE
-
- ERRORS
-
- ATTRIBUTES
-
- Multithreading (see pthreads(7))
-
- CONFORMING TO
-
- NOTES
-
- EXAMPLE
-
- SEE ALSO
-
This document was created by
man2html,
using the manual pages.
Time: 02:54:57 GMT, September 18, 2014


Browse the repository below.
|
|
Wheat seedling root system X-ray CT scan
|
.STL |
Marcus Griffiths |
|
|
Maize root crown X-ray CT scan
|
.WRL |
Nate Ellis |
|
|
Red Oak (Quercus rubra) Tree petiole X-ray CT scan
|
.STL
Print optimized model
|
Craig Brodersen |
|
|
American Beech (Fagus grandifolia) Tree root X-ray CT scan
|
.STL
Print optimized model
|
Craig Brodersen |
|
|
White Ash (Fraxinus americana) Tree petiole X-ray CT scan
|
.STL
Print optimized model
|
Craig Brodersen |
|
|
White Ash (Fraxinus americana) Tree root X-ray CT scan
|
.STL
Print optimized model
|
Craig Brodersen |
|
|
Red Maple (Acer rubrum) Tree petiole X-ray CT scan
|
.STL
Print optimized model
|
Craig Brodersen |
|
|
White Pine (Pinus strobus) Tree wood X-ray CT scan
|
No model file available |
Craig Brodersen |
|
|
White ash tree growth rings X-ray CT scan
|
No model file available |
Jay Wason |
|
|
Pollen from Silver Birch (Betula pendula) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Cedar of Lebanon (Cedrus libani, Pinaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Deodar Cedar (Cedrus deodara, Pinaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Sweet Wormwood (Artemisia annua, Asteraceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Goat Willow (Salix caprea, Salicaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Small-leaved Lime (Tilia cordata, Malvaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Field Maple (Acer campestre, Sapindaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Woollyfruit Sedge (Carex lasiocarpa, Cyperaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Perennial Ragweed (Ambrosia psilostachya, Asteraceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Ivy (Hedera helix, Araliaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Goosefoot (Chenopodium album, Amaranthaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Meadow Clary (Salvia pratensis, Lamiaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Winter’s bark (Drimys winteri, Winteraceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from False Barley (Hordeum murinum, Poaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Atlas Cedar (Cedrus atlantica, Pinaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Sessile Oak (Quercus petraea, Fagaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Pedunculate Oak (Quercus robur, Fagaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Common Knapweed (Centaurea nigra, Asteraceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Ribwort (Plantago lanceolata, Plantaginaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Pollen from Hazel Tree (Corylus avellana, Betulaceae) confocal microscopy z-stacks
|
.STL
Print optimized model
|
Oliver Wilson |
|
|
Palmer Amaranth Shoot Pointcloud
|
.ply |
Ohio State University Art and Design |
|
|
Waterhemp Shoot Pointcloud
|
.OBJ |
Ohio State University Art and Design |
|
|
Marestail Shoot Pointcloud
|
.OBJ |
Ohio State University Art and Design |
|
|
Common Ragweed Shoot Pointcloud
|
.OBJ |
Ohio State University Art and Design |
|
|
Cabbage Shoot Pointcloud
|
No model file available |
Phenospex |
|
|
Sugar Beet Shoot Pointcloud
|
.PLY |
Phenospex |
|
|
Sugar Beet (NDVI) Shoot Pointcloud
|
.PLY |
Phenospex |
|
|
Arabidopsis Shoot Pointcloud
|
No model file available |
Phenospex |
|
|
Barley Shoot Pointcloud
|
No model file available |
Phenospex |
|
|
Maize Shoot Pointcloud
|
No model file available |
Phenospex |
|
|
Potato Shoot Pointcloud
|
No model file available |
Phenospex |
|
|
Canola Shoot Pointcloud
|
No model file available |
Phenospex |
|
|
Menara Tree LiDAR UAV Pointcloud
|
Pointcloud (.laz) |
Alexander Shenkin |
|
|
Plant cell with compartments cgi render
|
No model file available |
pavelmo4alov |
|
|
Eukaryotic Cell cgi render
|
No model file available |
The Center for BioMedical Visualization (SGU) |
If you know a model that is not listed on this repository, please fill out the form at the link below.


10
1 Dead flies make the perfumer's ointment give off a stench;
so a little folly outweighs wisdom and honor.
2 A wise man's heart inclines him to the right,
but a fool's heart to the left.
3 Even when the fool walks on the road, he lacks sense,
and he says to everyone that he is a fool.
4 If the anger of the ruler rises against you, do not leave your place,
for calmness will lay great offenses to rest.
5 There is an evil that I have seen under the sun, as it were an error proceeding from the ruler:
6 folly is set in many high places, and the rich sit in a low place.
7 I have seen slaves on horses, and princes walking on the ground like slaves.
8 He who digs a pit will fall into it,
and a serpent will bite him who breaks through a wall.
9 He who quarries stones is hurt by them,
and he who splits logs is endangered by them.
10 If the iron is blunt, and one does not sharpen the edge,
he must use more strength,
but wisdom helps one to succeed.
11 If the serpent bites before it is charmed,
there is no advantage to the charmer.
12 The words of a wise man's mouth win him favor,
but the lips of a fool consume him.
13 The beginning of the words of his mouth is foolishness,
and the end of his talk is evil madness.
14 A fool multiplies words,
though no man knows what is to be,
and who can tell him what will be after him?
15 The toil of a fool wearies him,
for he does not know the way to the city.
16 Woe to you, O land, when your king is a child,
and your princes feast in the morning!
17 Happy are you, O land, when your king is the son of the nobility,
and your princes feast at the proper time,
for strength, and not for drunkenness!
18 Through sloth the roof sinks in,
and through indolence the house leaks.
19 Bread is made for laughter,
and wine gladdens life,
and money answers everything.
20 Even in your thought, do not curse the king,
nor in your bedroom curse the rich,
for a bird of the air will carry your voice,
or some winged creature tell the matter.


|
Aufgabe 3 - Quo vadis, Quax?
|
General pathfinding manager More...
Public Member Functions | |
| delegate void | RequestMapTileEventHandler (Vector2Int sw_point) |
| Request map tile delegate More... | |
| delegate void | RequestSpecialSquareEventHandler (Vector2Int sw_point) |
| Request special square delegate More... | |
| delegate void | StartedPathfindingEventHandler () |
| Started pathfinding delegate More... | |
| delegate void | FinishedPathfindingEventHandler (List< Node > path, bool foundPath) |
| Finished pathfinding delegate More... | |
| void | SetupPathfinding (Vector2Int start, Vector2Int target) |
| Setup pathfinding More... | |
| void | UpdateGrid (List< MapSquare > updatedSquares, Vector2Int sw_point, ref bool updated) |
| Update the PathfindingGrid More... | |
| void | FindPath (bool canWalkUnknown) |
| Try find a path to the _targetNode More... | |
Public Attributes | |
| Grid | PathfindingGrid |
| The grid used for pathfinding More... | |
| double | TotalTimeUpdateGrid |
| The total execution time spent while updating the PathfindingGrid More... | |
| double | TotalTimePathfinding01 |
| The total execution time spent pathfinding with unknown nodes as unwalkable More... | |
| double | TotalTimePathfinding02 |
| The total execution time spent pathfinding with unknown nodes as walkable More... | |
Properties | |
| static PathfindingManager | Instance [get] |
| The Singleton Instance More... | |
Events | |
| StartedPathfindingEventHandler | StartedPathfinding |
| Started pathfinding event More... | |
| RequestMapTileEventHandler | RequestedMapTile |
| Request map tile of quadtree event More... | |
| RequestSpecialSquareEventHandler | RequestSpecialSquare |
| Request map tile outside of quadtree event More... | |
| FinishedPathfindingEventHandler | FinishedPathfinding |
| Finished pathfinding event More... | |
General pathfinding manager
|
inline |
Try find a path to the _targetNode
| canWalkUnknown | Are unknown nodes considered walkable |
DONE
Check all neighbours
| delegate void Algorithm.Pathfinding.PathfindingManager.FinishedPathfindingEventHandler | ( | List< Node > | path, |
| bool | foundPath | ||
| ) |
Finished pathfinding delegate
| path | List of nodes forming the path |
| foundPath | Was a path found |
| delegate void Algorithm.Pathfinding.PathfindingManager.RequestMapTileEventHandler | ( | Vector2Int | sw_point | ) |
Request map tile delegate
| sw_point | The South-West (Bottom-Left) position of the requested map tile |
| delegate void Algorithm.Pathfinding.PathfindingManager.RequestSpecialSquareEventHandler | ( | Vector2Int | sw_point | ) |
Request special square delegate
| sw_point | The South-West (Bottom-Left) position of the requested map tile |
|
inline |
Setup pathfinding
| start | The start position |
| target | The target position |
| delegate void Algorithm.Pathfinding.PathfindingManager.StartedPathfindingEventHandler | ( | ) |
Started pathfinding delegate
|
inline |
Update the PathfindingGrid
| updatedSquares | List of updated squares |
| sw_point | The South-West (Bottom-Left) point of the searched square |
| updated | Was the grid updated |
| Grid Algorithm.Pathfinding.PathfindingManager.PathfindingGrid |
The grid used for pathfinding
| double Algorithm.Pathfinding.PathfindingManager.TotalTimePathfinding01 |
The total execution time spent pathfinding with unknown nodes as unwalkable
| double Algorithm.Pathfinding.PathfindingManager.TotalTimePathfinding02 |
The total execution time spent pathfinding with unknown nodes as walkable
| double Algorithm.Pathfinding.PathfindingManager.TotalTimeUpdateGrid |
The total execution time spent while updating the PathfindingGrid
|
staticget |
The Singleton Instance
| FinishedPathfindingEventHandler Algorithm.Pathfinding.PathfindingManager.FinishedPathfinding |
Finished pathfinding event
| RequestMapTileEventHandler Algorithm.Pathfinding.PathfindingManager.RequestedMapTile |
Request map tile of quadtree event
| RequestSpecialSquareEventHandler Algorithm.Pathfinding.PathfindingManager.RequestSpecialSquare |
Request map tile outside of quadtree event
| StartedPathfindingEventHandler Algorithm.Pathfinding.PathfindingManager.StartedPathfinding |
Started pathfinding event


| First Seen | WildFire Verdict | SHA256 | File Size (Bytes) | File Type | Tags |
|---|---|---|---|---|---|
| 03/21/2017 12:16:51pm | Malware | 202196645cbfb2c225ab594575957dce411718b67c531a76b4431d16ccc392e4 | 55,296 | PE |
WildFireTest
|
{% block title %}
| First Seen | WildFire Verdict | SHA256 | File Size (Bytes) | File Type | Tags |
|---|---|---|---|---|---|
| 03/21/2017 12:16:51pm | Malware | 202196645cbfb2c225ab594575957dce411718b67c531a76b4431d16ccc392e4 | 55,296 | PE |
WildFireTest
|