Proud day as Stafford Rugby Club unveils new multi-million stadium
There were smiles all around as a rugby club unveiled its new stadium which has been 30 years in the making.
by Jamie BrassingtonProud Stafford Rugby Club members were beaming as they attended the unveiling of the stadium on Blackberry Lane, Stafford, which has cost millions of pounds to build.
Club president David Ainge said: "It is fantastic to see the stadium open today. We broke ground 18-months-ago but this has been 30 years in the making.
"I was one of the first involved in the negotiations 30 years ago with Lord Stafford.
"There has been frustration's, some difficulties, but we have overcome it with the help of lots of people, especially the developers and the designers.
"As you can see, it is a fantastic facility. It is something to be proud of. I don't think there is many rugby facilities of this standard in the Midlands.
The land is owned by Lord Stafford, Francis Fitzherbert. He also owned the land of the club's previous stadium in Castlefields.
Among the brand new facilities includes four playing pitches, a large suite, a public bar, gymnasium, a home team dressing room and an away dressing room.
The main corridor through the building is lined with rugby shirts from past players. Shirts range from Gloucester to representing the armed services.
Hanging on a high over the main entrance is a large painting of Twickenham, which was gifted to the club by the stadium.
The design of the stadium has incorporated splashes of golden yellow and black in places, which is a nod to the club's playing colours.
The new stadium has allowed the club to develop more teams.
"Not just senior, it means a lot for junior rugby," he said. "We have a junior section of 300 children plus. We have also started a group of young ladies, under 18s, which we call Stafford Rose. We have got 79 members at the moment, which I think is the second highest in Staffordshire, and we only started 18 months ago.
"Recently in the last two weeks, we have resurrected the ladies team. So it is thriving. The important part, as well as rugby, is we are in the middle of the community.
"And we are working with them to use the facilities. They can use them. they can become social members. Obviously we will be looking to increase playing membership.
"Everything is geared for development on and off the pitch. That is what we want to do."


We love cartography because it draws from art, science, and technology. In the Cart Lab, we conduct mixed-methods research on the design and use of maps and visualizations. Our research crosses theoretical, methodological, organizational, and technological dimensions of the discipline, and contributes to the sibling disciplines of geography, GIScience, human-computer interaction, information visualization, and visual analytics.
Much of the empirical research in cartography over the past half century addressed representation design, evaluating how maps visually encode geographic information from perceptual, cognitive, and social/critical perspectives. We remain active in the study of cartographic design, particularly in the face of evolving mapping technologies and professional practices. Our recent research on cartographic representation includes aesthetics and style, bivariate and multivariate mapping, multiscale generalization, semiotics, terrain representation, and uncertainty visualization, among other topics. View our work on cartographic design…
Increasingly, cartographers need both to encode geographic information as well as code a useful and usable interface for exploring the resulting maps. But interface design is much more than pushing 0s and 1s, and few time-tested principles exist to inform design of the user experience. Increasingly, we contribute to interaction science, approaching topics such as cartographic interaction primitives (i.e., the building blocks of an interactive map), interface flexibility versus constraint, user expertise and motivation, coordinated multiview geovisualization, and applications of interactive mapping to support geography. View our work on UX/UI design…
Interactive maps increasingly are used online or through mobile devices. Accordingly, much of the canon of cartographic design principles needs to be revised or completely rethought due to the contemporary design and use context. Our production, research, and education intersects at how we think about a web-enabled and mobile platform, pushing the boundaries of the underlying software and hardware technologies while considering new users and use contexts. View our work on web and mobile map design
We couple our interests in interactive, online, and mobile mapping with a methodological contribution on the process of map design. Design is a process, and the digital revolution has introduced new design considerations and metrics of success. We draw from usability engineering and user-centered design to streamline workflows for taking a design from concept to deployment. Further, we adapt methods pioneered in social science for the discount evaluation of maps, enabling rapid user feedback throughout the design process. View our work on usability engineering and user-centered design…
The production of maps and geographic information is couched within a broader political economy that impacts their design and accessibility. We work with a range of government agencies and industry firms to understand institutional barriers and technological path dependencies that impact design. Further, we support open source and participatory mapping projects, bringing map technology to underserved communities and student populations.
Cartographic Design
User Interface & User Experience (UI/UX) Design
Web & Mobile Map Design
Usability Engineering & User-centered Design
Pedagogical Research
Organizational Management
Featured Research Projects


Associate Professor of Artificial Intelligence
and Data Science at ISAE-Supaero, University of Toulouse
I research evolution and learning in artificial systems.
I teach data science and evolutionary computation.
I work on applications in climate change and renewable energy.


{{ partial "head" . }}
shopping_cart
expand_more
close
Products
Canvas prints
Framed prints
Triptych prints
Photo collages
Photo magnets
Throw pillows
Photo pillows
(new)
Gifts
Deals
{{ block "main" . }}{{ end }}
{{ partial "footer" . }}


Futures for Crystal
Futures provide a nice way to reason about performing many operations in parallel– in an efficient and non-blocking way. The idea is simple, a Future is a sort of a placeholder object that you can create for a result that does not yet exist. Generally, the result of the Future is computed concurrently and can be later collected. Composing concurrent tasks in this way tends to result in faster, asynchronous, non-blocking parallel code.
** Source : http://docs.scala-lang.org/overviews/core/futures.html
Usage
require "futures"
include Futures
# Create a new future
a = Future.new do
someTimeConsumingOperation()
end
# Register a callback on successful operation
a.on_success do |val|
doSomethingWithResult val
end
a.on_failure do |err|
raise err
end
# Or handle both cases in one callback
a.on_complete do |result|
try = result.get
case try
when Success
puts try.get
when Failure
raise try.error
end
end
# Or block until future completes
val = a.get
# compose new Futures from existing ones
b = a.map do |val|
"String : " + val
end
b.get


Jobs was born on February 24, 1955, in San Francisco, California. He lived with his adoptive family in Mountain View, California, within the area that would later become known as Silicon Valley. As a boy, Jobs and his father worked on electronics in the family garage. Paul showed his son how to take apart and reconstruct electronics, a hobby that instilled confidence, tenacity and mechanical prowess in young Jobs.
While Jobs was always an intelligent and innovative thinker, his youth was riddled with frustrations over formal schooling. Jobs was a prankster in elementary school due to boredom, and his fourth-grade teacher needed to bribe him to study. Jobs tested so well, however, that administrators wanted to skip him ahead to high school — a proposal that his parents declined. After high school, Jobs enrolled at Reed College in Portland, Oregon. Lacking direction, he dropped out of college after six months and spent the next 18 months dropping in on creative classes at the school. Jobs later recounted how one course in calligraphy developed his love of typography. In 1974, Jobs took a position as a video game designer with Atari. Several months later he left the company to find spiritual enlightenment in India, traveling further and experimenting with psychedelic drugs.
In 1976, when Jobs was just 21, he and Wozniak started Apple Computer in the Jobs’ family garage. They funded their entrepreneurial venture by Jobs selling his Volkswagen bus and Wozniak selling his beloved scientific calculator. Jobs and Wozniak are credited with revolutionizing the computer industry with Apple by democratizing the technology and making machines smaller, cheaper, intuitive and accessible to everyday consumers. Wozniak conceived of a series of user-friendly personal computers, and — with Jobs in charge of marketing — Apple initially marketed the computers for $666.66 each. The Apple I earned the corporation around $774,000. Three years after the release of Apple's second model, the Apple II, the company's sales increased by 700 percent to $139 million. In 1980, Apple Computer became a publicly-traded company, with a market value of $1.2 billion by the end of its very first day of trading. Jobs looked to marketing expert John Sculley of Pepsi-Cola to take over the role of CEO for Apple. The next several products from Apple suffered significant design flaws, however, resulting in recalls and consumer disappointment. IBM suddenly surpassed Apple in sales, and Apple had to compete with an IBM/PC-dominated business world.


Poutines (Pyro Coroutines)¶
BlockPoutine¶
-
class
BlockPoutine
(fn, hide_all=True, expose_all=False, hide=None, expose=None, hide_types=None, expose_types=None)¶ Bases:
pyro.poutine.poutine.Poutine
This Poutine selectively hides pyro primitive sites from the outside world.
For example, suppose the stochastic function fn has two sample sites “a” and “b”. Then any poutine outside of BlockPoutine(fn, hide=[“a”]) will not be applied to site “a” and will only see site “b”:
>>> fn_inner = TracePoutine(fn) >>> fn_outer = TracePoutine(BlockPoutine(TracePoutine(fn), hide=["a"])) >>> trace_inner = fn_inner.get_trace() >>> trace_outer = fn_outer.get_trace() >>> "a" in trace_inner True >>> "a" in trace_outer False >>> "b" in trace_inner True >>> "b" in trace_outer True
BlockPoutine has a flexible interface that allows users to specify in several different ways which sites should be hidden or exposed. See the constructor for details.
ConditionPoutine¶
-
class
ConditionPoutine
(fn, data)¶ Bases:
pyro.poutine.poutine.Poutine
Adds values at observe sites to condition on data and override sampling
EscapePoutine¶
-
class
EscapePoutine
(fn, escape_fn)¶ Bases:
pyro.poutine.poutine.Poutine
Poutine that does a nonlocal exit by raising a util.NonlocalExit exception
LambdaPoutine¶
-
class
CondIndepStackFrame
(name, counter, vectorized)¶ Bases:
tuple
-
counter
¶ Alias for field number 1
-
name
¶ Alias for field number 0
-
vectorized
¶ Alias for field number 2
-
-
class
LambdaPoutine
(fn, name, scale, vectorized)¶ Bases:
pyro.poutine.poutine.Poutine
- This poutine has two functions:
- handle score-rescaling
- keep track of stack of nested map_datas at each sample/observe site for the benefit of TracePoutine; necessary information passed via map_data_stack in msg
LiftPoutine¶
-
class
LiftPoutine
(fn, prior)¶ Bases:
pyro.poutine.poutine.Poutine
Poutine which “lifts” parameters to random samples. Given a stochastic function with param calls and a prior, creates a stochastic function where all param calls are replaced by sampling from prior.
Prior should be a callable or a dict of names to callables.
Poutine¶
-
class
Poutine
(fn)¶ Bases:
object
Context manager class that modifies behavior and adds side effects to stochastic functions i.e. callables containing pyro primitive statements.
See the Poutine execution model writeup in the documentation for a description of the entire Poutine system.
This is the base Poutine class. It implements the default behavior for all pyro primitives, so that the joint distribution induced by a stochastic function fn is identical to the joint distribution induced by Poutine(fn).
ReplayPoutine¶
-
class
ReplayPoutine
(fn, guide_trace, sites=None)¶ Bases:
pyro.poutine.poutine.Poutine
Poutine for replaying from an existing execution trace.
Trace¶
-
class
Trace
(*args, **kwargs)¶ Bases:
networkx.classes.digraph.DiGraph
Execution trace data structure
-
add_node
(site_name, *args, **kwargs)¶ Parameters: site_name (string) – the name of the site to be added Adds a site to the trace.
Identical to super(Trace, self).add_node, but raises an error when attempting to add a duplicate node instead of silently overwriting.
-
batch_log_pdf
(site_filter=<function <lambda>>)¶ Compute the batched local and overall log-probabilities of the trace.
The local computation is memoized, and also stores the local .log_pdf().
-
compute_batch_log_pdf
(site_filter=<function <lambda>>)¶ Compute the batched local log-probabilities at each site of the trace.
The local computation is memoized, and also stores the local .log_pdf().
-
copy
()¶ Makes a shallow copy of self with nodes and edges preserved. Identical to super(Trace, self).copy(), but preserves the type and the self.graph_type attribute
-
log_pdf
(site_filter=<function <lambda>>)¶ Compute the local and overall log-probabilities of the trace.
The local computation is memoized.
Returns: total log probability. Return type: torch.autograd.Variable
-
node_dict_factory
¶ alias of
OrderedDict
-
nonreparam_stochastic_nodes
¶ Gets a list of names of sample sites whose stochastic functions are not reparameterizable primitive distributions
-
observation_nodes
¶ Gets a list of names of observe sites
-
reparameterized_nodes
¶ Gets a list of names of sample sites whose stochastic functions are reparameterizable primitive distributions
-
stochastic_nodes
¶ Gets a list of names of sample sites
-
TracePoutine¶
-
class
TracePoutine
(fn, graph_type=None)¶ Bases:
pyro.poutine.poutine.Poutine
Execution trace poutine.
A TracePoutine records the input and output to every pyro primitive and stores them as a site in a Trace(). This should, in theory, be sufficient information for every inference algorithm (along with the implicit computational graph in the Variables?)
We can also use this for visualization.
-
get_trace
(*args, **kwargs)¶ Returns: data structure Return type: pyro.poutine.Trace Helper method for a very common use case. Calls this poutine and returns its trace instead of the function’s return value.
-
-
get_vectorized_map_data_info
(trace)¶ This determines whether the vectorized map_datas are rao-blackwellizable by TraceGraph_ELBO. This also gathers information to be consumed by downstream by TraceGraph_ELBO.
-
identify_dense_edges
(trace)¶ Modifies a trace in-place by adding all edges based on the map_data_stack information stored at each site.


Confirm function is a promise-returning wrapper around alertify.js. See the code for configuring and usig the confirm-click module below.


Welcome!
I attended Electrical Engineering courses for two and a half years at the following colleges:
- Highline College
- University of Washington Seattle
I have had the following (unofficial) jobs before:
- Calculus Tutor
- Lumberjack
My top ten favorite things to do in a game of basketball are:
- Shoot a clean three-pointer in a defender's face
- Euro-step between two defenders, with the last step giving enough air to reach a lay-up on the basket
- Swat a defenders' three-point shot right in front of them
- Cross a defender while driving the ball to the basket, finish with a contested lay-up
- Swat a defenders' layup from the side or behind while they are driving to the basket and release the ball for a layup or shot
- Fake a defender out by pivoting on one foot to sell the fake shot, spin back around and pivot on other foot, finish with a drive and lay-up straight to the basket
- Drive to the basket, slow down near the free-throw line, and go for a jumper on the basket while a defender gets faked out by the drive
- If basket is heavily contended, drive with the ball to the right-side of the court, and while running, jump up in the air and use both hands to throw ball with more force than usual towards the basket, to combat the momentum of moving to the side
- Have shoelaces get untied while very tired, so that the whole game can be paused and I can recover my breath while retying my shoe
- Usually play like trash because the above things very rarely happen


Nonlinear optimization
The intuitive explanation about Lagrangian duality in optimization
Please check here for the nice geometric explanation. And here for the mathematical explanation.
Nonlinear optimization
The nonlinear optimization can be written as
where is a nonlinear function w.r.t. . Since the can be extremely complicated, we may not be able to explicitly figure out the analytical solution of . Instead of the analytical solution, we usually apply iteration methods to optimize the objective, even though it may fall into local optimal.
There are four iteration methods: Gradient Descent, Newton method, Gauss-Newton method, Levenberg–Marquardt (LM).
Gradient Descent
Given a step size hyperparameter , the update rule is
This optimization strategy (but a variant SGD) has been widely adopted in various neural network update.
Newton method
Newton method try to solve this objective
It applies the Taylor expansion Note that the Jaconbian J(x) and Hessian H(x) are first and second derivation of F(x) w.r.t. x
To minimize above equation, we calculate the gradient w.r.t. and make it equal to 0. We have
However, the second derivation is usually expensive to calculate
Gauss-Newton
Gauss-Newton solve the problem from least-square perspective. , which is a scalar number, usually come from , where is a vector. This method apply taylor expansion on to first derivation. We have
So
Calculating the gradient w.r.t. , we have Note that the Jaconbian J(x) and Hessian H(x) are first and second derivation of f(x) w.r.t. x. This is different with Newton method.
However, Gauss-Newton method still has problems. First, the needs to be invertible , but this is not guaranteed. Second, if is big, the above Taylor expansion is a bad approximation. To solve these two problems, LM method is invented.
Levenberg–Marquardt (LM)
The main motivation of LM is to control the size of update step . It optimizes the below objective
where is the confidence interval, which will be updated for each optimization step.
The update rule:
For each optimization step, we calculate
If is closed to 1, the local linear is guaranteed and the approximation is good. If is larger than 1, the actual decrease is more than the approximation which means the is accelerated decreasing. And we should set a bigger confidence interval to speed decrease. If is smaller than 1, the actual decrease is less than the approximation which means the is entering a flatted area. And we should set smaller confidence interval .
The above constrained objective can be converted to dual space by applying Lagrange multipler.
The optimal satisfies
If is big which means >0 and is over the confidence interval, the will be (i.e. Gradient Descent update). If is small, then the update is like Gauss-Newton .
A SGD variant: Adam
The LM method adaptively determines the update step. In gradient descent, there is also a famous adaptive method, called Adam, which has been widely used in neural network optimization. Here is Adam update rule Check here for others introduction. :
Usually, , is learning rate.
The first two equations are momentum update (i.e. moving average). The third and fourth equations are bias corrections. Because is underestimated at the beginning (i.e. ). will gradually decrease to 0 as the optimization proceed. The last equation is the parameter update rule. The learning rate will be adjusted by . Obviously, at the beginning is small ( is used to accumulate the gradient). But after many iterations, could be big, and thus the learning rate will be adjusted to 0.


{{ metadata.get('title') }} {% if metadata.get('unedited', false) %} [Unedited] {% endif %}
{{ render_byline() }}Introduction
Resource hints provide "hints" to the browser about what resources will be needed soon. The action that the browser takes as a result of receiving this hint will vary depending on the type of resource hint; different resource hints kick off different actions. When used correctly, they can improve page performance by giving a head start to important anticipated actions.
Examples of performance improvements as a result of resource hints include:
- Jabong decreased Time to Interactive by 1.5 seconds by preloading critical scripts.
- Barefoot Wine decreased Time to Interactive of future pages by 2.7 seconds by prefetching visible links.
- Chrome.com decreased latency by 0.7 seconds by preconnecting to critical origins.
There are four separate resource hints supported by most browsers today: dns-prefetch
, preconnect
, preload
, and prefetch
.
dns-prefetch
The role of dns-prefetch
is to initiate an early DNS lookup. It's useful for completing the DNS lookup for third-parties. For example, the DNS lookup of a CDN, font provider, or third-party API.
preconnect
preconnect
initiates an early connection, including DNS lookup, TCP handshake, and TLS negotiation. This hint is useful for setting up a connection with a third party. The uses of preconnect
are very similar to those of dns-prefetch
, but preconnect
has less browser support. However, if you don't need IE 11 support, preconnect is probably a better choice.
preload
The preload
hint initiates an early request. This is useful for loading important resources that would otherwise be discovered late by the parser. For example, if an important image is only discoverable once the browser has received and parsed the stylesheet, it may make sense to preload the image.
prefetch
prefetch
initiates a low-priority request. It's useful for loading resources that will be used on the subsequent (rather than current) page load. A common use of prefetch is loading resources that the application "predicts" will be used on the next page load. These predictions could be based on signals like user mouse movement or common user flows/journeys.
Syntax
97% of resource hint usage relied on using the <link>
tag to specify a resource hint. For example, <link rel="prefetch" href="shopping-cart.js">
.
Only 3% of resource hint usage used HTTP headers to specify resource hints. For example, Link: <https://example.com/shopping-cart.js>; rel=prefetch
.
Because the usage of resource hints in HTTP headers is so low, the remainder of this chapter will focus solely on analyzing the usage of resource hints in conjunction with the <link>
tag. However, it's worth noting that in future years, usage of resource hints in HTTP headers may increase as HTTP/2 Push is adopted. This is due to the fact that HTTP/2 Push has repurposed the HTTP preload Link
header as a signal to push resources.
Resource hints
| Resource Hint | Usage (percent of sites) |
|---|---|
dns-prefetch |
29% |
preload |
16% |
preconnect |
4% |
prefetch |
3% |
prerender (deprecated) |
0.13% |
The relative popularity of dns-prefetch
is unsurprising; it's a well-established API (it first appeared in 2009), it is supported by all major browsers, and it is the most "inexpensive" of all resource hints. Because dns-prefetch
only performs DNS lookups, it consumes very little data, and therefore there is very little downside to using it. dns-prefetch
is most useful in high-latency situations.
That being said, if a site does not need to support IE11 and below, switching from dns-prefetch
to preconnect
is probably a good idea. In an era where HTTPS is ubiquitous, preconnect
yields greater performance improvements while still being inexpensive. Note that unlike dns-prefetch
, preconnect
not only initiates the DNS lookup, but also the TCP handshake and TLS negotiation. The certificate chain is downloaded during TLS negotiation and this typically costs a couple of kilobytes.
prefetch
is used by 3% of sites, making it the least widely used resource hint. This low usage may be explained by the fact that prefetch
is useful for improving subsequent—rather than current—page loads. Thus, it will be overlooked if a site is only focused on improving their landing page, or the performance of the first page viewed.
| Resource Hint | Resource Hints Per Page: Median |
Resource Hints Per Page: 90th Percentile |
|---|---|---|
dns-prefetch |
2 | 8 |
preload |
2 | 4 |
preconnect |
2 | 8 |
prefetch |
1 | 3 |
prerender (deprecated) |
1 | 1 |
Resource hints are most effective when they're used selectively ("when everything is important, nothing is"). Figure 2 above shows the number of resource hints per page for pages using at least one resource hint. Although there is no clear cut rule for defining what an appropriate number of resource hints is, it appears that most sites are using resource hints appropriately.
The crossorigin
attribute
Most "traditional" resources fetched on the web (images, stylesheets, and scripts) are fetched without opting in to Cross-Origin Resource Sharing (CORS). That means that if those resources are fetched from a cross-origin server, by default their contents cannot be read back by the page, due to the same-origin policy.
In some cases, the page can opt-in to fetch the resource using CORS if it needs to read its content. CORS enables the browser to "ask permission" and get access to those cross-origin resources.
For newer resource types (e.g. fonts, fetch()
requests, ES modules), the browser defaults to requesting those resources using CORS, failing the requests entirely if the server does not grant it permission to access them.
crossorigin value |
Usage | Explanation |
|---|---|---|
| Not set | 92% | If the crossorigin attribute is absent, the request will follow the single-origin policy. |
| anonymous (or equivalent) | 7% | Executes a cross-origin request that does not include credentials. |
| use-credentials | 0.47% | Executes a cross-origin request that includes credentials. |
crossorigin
attribute as a percent of resource hint instances.In the context of resource hints, usage of the crossorigin
attribute enables them to match the CORS mode of the resources they are supposed to match and indicates the credentials to include in the request. For example: <link rel="prefetch" href="https://other-server.com/shopping-cart.css" crossorigin="anonymous">
enables CORS and indicates that no credentials should be included for those cross-origin requests.
Although other HTML elements support the crossorigin attribute, this analysis only looks at usage with resource hints.
The as
attribute
as
is an attribute that should be used with the preload
resource hint to inform the browser of the type (e.g. image, script, style, etc.) of the requested resource. This helps the browser correctly prioritize the request and apply the correct Content Security Policy (CSP). CSP is a security mechanism, expressed via HTTP header, that helps mitigate the impact of XSS and other malicious attacks by declaring a safelist of trusted sources; only content from these sources can be rendered or executed.
88% of resource hint instances use the as
attribute. When as
is specified, it is overwhelmingly used for scripts: 92% of usage is script, 3% font, and 3% styles. This is unsurprising given the prominent role that scripts play in most sites' architecture as well the high frequency with which scripts are used as attack vectors (thereby making it therefore particularly important that scripts get the correct CSP applied to them).
The future
At the moment, there are no proposals to expand the current set of resource hints. However, priority hints and native lazy loading are two proposed technologies that are similar in spirit to resource hints in that they provide APIs for optimizing the loading process.
Priority Hints
Priority hints are an API for expressing the fetch priority of a resource a resource: high
, low
, or auto
. They can be used with a wide range of HTML tags: specifically <image>
, <link
>,


Introduction to naz¶
naz is an async SMPP client. It’s name is derived from Kenyan hip hop artiste, Nazizi.
SMPP is a protocol designed for the transfer of short message data between External Short Messaging Entities(ESMEs), Routing Entities(REs) and Short Message Service Center(SMSC). - Wikipedia
naz is in active development and it’s API may change in backward incompatible ways.
Table of Contents
1 Installation¶
pip install naz
2.1 As a library¶
import asyncio
import naz
loop = asyncio.get_event_loop()
broker = naz.broker.SimpleBroker(maxsize=1000)
cli = naz.Client(
smsc_host="<IP_ADDRESS>",
smsc_port=2775,
system_id="smppclient1",
password="password",
broker=broker,
)
# queue messages to send
for i in range(0, 4):
print("submit_sm round:", i)
msg = naz.protocol.SubmitSM(
short_message="Hello World-{0}".format(str(i)),
log_id="myid12345",
source_addr="254722111111",
destination_addr="254722999999",
)
loop.run_until_complete(
cli.send_message(msg)
)
try:
# 1. connect to the SMSC host
# 2. bind to the SMSC host
# 3. send any queued messages to SMSC
# 4. read any data from SMSC
# 5. continually check the state of the SMSC
tasks = asyncio.gather(
cli.connect(),
cli.tranceiver_bind(),
cli.dequeue_messages(),
cli.receive_data(),
cli.enquire_link(),
)
loop.run_until_complete(tasks)
except Exception as e:
print("exception occured. error={0}".format(str(e)))
finally:
loop.run_until_complete(cli.unbind())
loop.stop()
NB:
For more information about all the parameters that naz.Client can take, consult the docs
More examples can be found here
if you need an SMSC server/gateway to test with, you can use the docker-compose file in the
naz
repo to bring up an SMSC simulator. That docker-compose file also has a redis and rabbitMQ container if you would like to use those as your naz.broker.BaseBroker.
2.2 As a cli app¶
naz
also ships with a commandline interface app called naz-cli
(it is also installed by default when you pip install naz).
create a python config file, eg; /tmp/my_app.py
import naz
from myfile import ExampleBroker
client = naz.Client(
smsc_host="<IP_ADDRESS>",
smsc_port=2775,
system_id="smppclient1",
password="password",
broker=ExampleBroker()
)
and a python file, myfile.py (in the current working directory) with the contents:
import asyncio
import naz
class ExampleBroker(naz.broker.BaseBroker):
def __init__(self):
loop = asyncio.get_event_loop()
self.queue = asyncio.Queue(maxsize=1000, loop=loop)
async def enqueue(self, message):
self.queue.put_nowait(message)
async def dequeue(self):
return await self.queue.get()
then run:
naz-cli --client tmp.my_app.client
NB:
The
naz
config file(ie, the dotted path we pass in tonaz-cli --client
) is any python file that has a naz.Client instance declared in it.
More examples can be found; examples As an example, start the SMSC simulator(
docker-compose up
) then in another terminal run,naz-cli --client examples.example_config.client
3.1 async everywhere¶
import naz
import asyncio
loop = asyncio.get_event_loop()
broker = naz.broker.SimpleBroker(maxsize=1000)
cli = naz.Client(
smsc_host="<IP_ADDRESS>",
smsc_port=2775,
system_id="smppclient1",
password="password",
broker=broker,
)
3.2.1 logging¶
naz
you have the ability to annotate all the log events that naz will generate with anything you want.import naz
logger = naz.log.SimpleLogger(
"naz.client",
log_metadata={ "environment": "production", "release": "v5.6.8"}
)
cli = naz.Client(
...
logger=logger,
)
naz
also gives you the ability to supply your own logger. All you have to do is pass in a python logging.Loggernaz
to use key=value style of logging, then just create a logger that does just that:import naz
class KVlogger(logging.Logger):
"""
A simple implementation of a key=value
log renderer.
"""
def __init__(self, name, level=logging.INFO):
super(KVlogger, self).__init__(name, level)
handler = logging.StreamHandler()
formatter = logging.Formatter("%(message)s")
handler.setFormatter(formatter)
self.addHandler(handler)
self.setLevel("DEBUG")
def log(self, level, msg, *args, **kwargs):
new_msg = self._process_msg(msg)
return super(KVlogger, self).log(level, new_msg, *args, **kwargs)
def _process_msg(self, message):
# implementation of key=value log renderer
new_msg = ", ".join("{0}={1}".format(k, v) for k, v in message.items())
return new_msg
kvLog = KVlogger()
cli = naz.Client(
...
logger=kvLog,
)
3.2.2 hooks¶
naz
will call the to_smsc method just before sending data to SMSC and also call the from_smsc method just after getting data from SMSC.naz.hooks.SimpleHook
which just logs the request and response.import naz
from prometheus_client import Counter
class MyPrometheusHook(naz.hooks.BaseHook):
async def to_smsc(self, smpp_command, log_id, hook_metadata, pdu):
c = Counter('my_requests', 'Description of counter')
c.inc() # Increment by 1
async def from_smsc(self,
smpp_command,
log_id,
hook_metadata,
status,
pdu):
c = Counter('my_responses', 'Description of counter')
c.inc() # Increment by 1
myHook = MyPrometheusHook()
cli = naz.Client(
...
hook=myHook,
)
another example is if you want to update a database record whenever you get a delivery notification event;
import sqlite3
import naz
class SetMessageStateHook(naz.hooks.BaseHook):
async def to_smsc(self, smpp_command, log_id, hook_metadata, pdu):
pass
async def from_smsc(self,
smpp_command,
log_id,
hook_metadata,
status,
pdu):
if smpp_command == naz.SmppCommand.DELIVER_SM:
conn = sqlite3.connect('mySmsDB.db')
c = conn.cursor()
t = (log_id,)
# watch out for SQL injections!!
c.execute("UPDATE SmsTable SET State='delivered' WHERE CorrelatinID=?", t)
conn.commit()
conn.close()
stateHook = SetMessageStateHook()
cli = naz.Client(
...
hook=stateHook,
)
3.2.3 integration with bug trackers¶
naz
with sentry, all you have to do is import and init the sentry sdk. A good place to do that would be in the naz config file, ie;/tmp/my_config.py
import naz
from myfile import ExampleBroker
import sentry_sdk # import sentry SDK
<EMAIL_ADDRESS>my_naz_client = naz.Client(
smsc_host="<IP_ADDRESS>",
smsc_port=2775,
system_id="smppclient1",
password="password",
broker=ExampleBroker()
)
naz-cli --client tmp.my_config.my_naz_client
3.3 Rate limiting¶
naz
lets you do this, by allowing you to specify a custom rate limiter.naz.ratelimiter.SimpleRateLimiter
import naz
myLimiter = naz.ratelimiter.SimpleRateLimiter(send_rate=35)
cli = naz.Client(
...
rate_limiter=myLimiter,
)
3.4 Throttle handling¶
The way naz handles throtlling is via Throttle handlers. A throttle handler is a class that implements the naz.throttle.BaseThrottleHandler interface
By default naz uses naz.throttle.SimpleThrottleHandler
to handle throttling.
As an example if you want to deny outgoing requests if the percentage of throttles is above 1.2% over a period of 180 seconds and the total number of responses from SMSC is greater than 45, then;
from naz.throttle import SimpleThrottleHandler
throttler = SimpleThrottleHandler(sampling_period=180,
sample_size=45,
deny_request_at=1.2)
cli = naz.Client(
...
throttle_handler=throttler,
)
3.5 Broker¶
How does your application and naz talk with each other?
It’s via a broker interface. Your application queues messages to a broker, naz
consumes from that broker and then naz sends those messages to SMSC/server.
You can implement the broker mechanism any way you like, so long as it satisfies the naz.broker.BaseBroker interface
naz.broker.SimpleBroker
naz.broker.SimpleBroker
should only be used for demo/test purposes.An example of using that broker;
import asyncio
import naz
loop = asyncio.get_event_loop()
my_broker = naz.broker.SimpleBroker(maxsize=1000) # can hold upto 1000 items
cli = naz.Client(
...
broker=my_broker,
)
try:
# 1. connect to the SMSC host
# 2. bind to the SMSC host
# 3. send any queued messages to SMSC
# 4. read any data from SMSC
# 5. continually check the state of the SMSC
tasks = asyncio.gather(
cli.connect(),
cli.tranceiver_bind(),
cli.dequeue_messages(),
cli.receive_data(),
cli.enquire_link(),
)
loop.run_until_complete(tasks)
except Exception as e:
print("exception occured. error={0}".format(str(e)))
finally:
loop.run_until_complete(cli.unbind())
loop.stop()
then in your application, queue items to the queue;
# queue messages to send
for i in range(0, 4):
msg = naz.protocol.SubmitSM(
short_message="Hello World-{0}".format(str(i)),
log_id="myid12345",
source_addr="254722111111",
destination_addr="254722999999",
)
loop.run_until_complete(
cli.send_message(msg)
)
then in your application, queue items to the queue;
# queue messages to send
for i in range(0, 4):
msg = naz.protocol.SubmitSM(
short_message="Hello World-{0}".format(str(i)),
log_id="myid12345",
source_addr="254722111111",
destination_addr="254722999999",
)
loop.run_until_complete(
cli.send_message(msg)
)
4 Benchmarks¶
Benchmarks can be found; benchmarks


Scout Hawk
Product Design Studio
<EMAIL_ADDRESS>Scout Hawk Product Design Studio is the independent digital product design consultancy of Zac Halbert. Learn more about Zac's design work here, or get in touch:
Scout Hawk Product Design Studio is the independent digital product design consultancy of Zac Halbert. Learn more about Zac's design work here, or get in touch: