libcidr is a library to make it easier to handle IP addresses and blocks, and manipulate them in various ways.
The core of the library is a pair of functions that take a human readable string and turn it into our internal representation of a CIDR address block (cidr_from_str() ), and one to take that internal representation and turn it into a human-readable string (cidr_to_str() ). There are a large number of options for how to format that string, as well.
Additionally, there are functions to compare different CIDR blocks, to determine if they're equal, or if one is contained within the other. This functionality can be useful for writing access-control code, or client-dependant configuration, or similar things. There are functions to manipulate address blocks and determine attributes of them, like network/broadcast addresses, the range of host addresses, the number of available host addresses, etc. There are functions to split a CIDR block into the two smaller blocks it contains, or to derive the parent block that it is itself contained within. And there are functions to translate to and from in_addr-type structures, which the operating system commonly uses to represent addresses for handle socket connections and so forth.
In short, just about anything you might do in a program with IP addressing, whether referring to individual hosts, or to any sized subnets, libcidr is designed to simplify handling. It's not a DNS library, nor is it a socket abstraction layer. It's just a set of functions for manipulating raw IP addresses in various ways.
The functions generally follow standard C conventions. They tend to return 0 or a pointer when acting properly, and -1 or NULL when something went wrong (unless the function usage suggests other returns, of course, as in cidr_get_pflen() ). They set errno when returning an error; the error codes each function can return are documented with the function.
libcidr doesn't use any threading itself. It should, however, be safe to use in any threaded program if used sensibly. Only a very few functions use static strings, and those that do (cidr_version() and cidr_numaddr() and its related functions being the only ones I can think of) tend to be constant strings as well, so they wouldn't be changing. Of course, you don't want to cidr_free() a CIDR in one thread while you're still using it in another, but if you do, it's not libcidr's fault.
For the current version or any extra information, see the libcidr project homepage, at <http://www.over-yonder.net/~fullermd/projects/libcidr>.
This reference manual is build using the codelibrary SGML DTD, which is specifically designed for documenting libraries. See the codelibrary homepage at <http://www.over-yonder.net/~fullermd/projects/sgml/codelibrary> for more details on it.
This datatype is intended for internal use only
Note:
Use the cidr_free() function to free the memory associated with this datatype, and the cidr_alloc() function to allocate and initialize the structure.
Generate a CIDR structure describing the broadcast address of the passed-in netblock.
Note that using this with an IPv6 netblock is technically asking for something that doesn't exist, since IPv6 doesn't have subnet broadcast addresses. This function will still return the all-1's address though, on the assumption that if you're asking the question, it's the answer you want.
An additional somewhat specialized case is that of an IPv4 /31 or IPv6 /127. Depending on your interpretation and usage, this is either a useless subnet since it only contains network and broadcast and no hosts, or a subnet that holds 2 hosts with neither network or broadcast address (commonly used for point-to-point links). As a result, cidr_addr_broadcast() and cidr_addr_network() will give answers as if it were a host-less subnet, while cidr_addr_hostmax() and cidr_addr_hostmin() will answer as though it were a 2-host subnet. It can be seen as a little strange for cidr_addr_broadcast() and cidr_addr_hostmax() to give the same answer, but as above, libcidr assumes that if you ask the question, you want the answer that makes sense in that context.
Similar caveats apply to calling these on a v4 /32 or v6 /128.
CIDR *
Returns a pointer to a CIDR structure describing the broadcast address on success. Returns NULL on failure.
Note:
cidr_addr_broadcast() can also fail and set errno for any of the reasons listed for cidr_alloc() .
Generate a CIDR structure describing the highest-numbered address available for a host IP in the given netblock.
See the discussion under cidr_addr_broadcast() concerning near- amd maximal-prefix-length blocks for edge case details.
The returned structure should be cleaned up using cidr_free() .
CIDR *
Returns a pointer to a CIDR structure describing the max host address on success. Returns NULL on failure.
Note:
cidr_addr_hostmax() can fail and set errno for any of the reasons listed for cidr_addr_broadcast() .
Generate a CIDR structure describing the lowest-numbered address available for a host IP in the given netblock.
See the discussion under cidr_addr_broadcast() concerning near- amd maximal-prefix-length blocks for edge case details.
The returned structure should be cleaned up using cidr_free() .
CIDR *
Returns a pointer to a CIDR structure describing the min host address on success. Returns NULL on failure.
Note:
cidr_addr_hostmin() can fail and set errno for any of the reasons listed for cidr_addr_network() .
Generate a CIDR structure describing the network address of the passed-in netblock.
See the discussion under cidr_addr_broadcast() concerning near- amd maximal-prefix-length blocks for edge case details.
The returned structure should be cleaned up using cidr_free() .
CIDR *
Returns a pointer to a CIDR structure describing the network address on success. Returns NULL on failure.
Note:
cidr_addr_network() can also fail and set errno for any of the reasons listed for cidr_alloc() .
Allocate memory for a CIDR structure and initialize the necessary pieces.
The returned structure should be cleaned up using cidr_free() .
Note that you should probably never need to call this function yourself; you'll generally get your CIDR structures as a return from a function like cidr_from_str() or cidr_from_inaddr() .
CIDR *
Returns a pointer to an initialized CIDR structure on success. Returns NULL on failure.
This function is passed two CIDR structures describing a pair of netblocks. It then determines if the latter is wholly contained within the former.
A common use-case of this will generally involve the second "block" actually being a host (/32 or /128) address, as when you're implementing ACL's. But that's really just a specific case of the second block being any other size; there's nothing special or magical about it. As far as libcidr is concerned, they're just two netblocks.
int
Returns 0 if little is wholly contained within big. Returns -1 if it's not, or if an error occured.
Allocate a CIDR , and fill it in with a duplicate of the information given.
The returned structure should be cleaned up using cidr_free() .
CIDR *
Returns a CIDR struct containing a copy of src. Returns NULL on failure.
Note:
cidr_dup() can fail and set errno for any of the reasons listed for cidr_alloc() .
Takes a populated struct in_addr, as you'd get from accept() or getaddrinfo() or similar functions. Parses it out and generates a CIDR structure based on it. Note that an in_addr only contains a host address, so the netmask is initialized to all-1's (/32).
CIDR *
Returns a pointer to a populated CIDR containing the address in the passed-in struct in_addr. The netmask is initialized to all-1's, and the protocol to IPv4. Use cidr_free() to free the structure when you're finished with it. Returns NULL on error.
Note:
cidr_from_inaddr() can also fail and set errno for any of the reasons listed for cidr_alloc() .
Takes a populated struct in6_addr, as you'd get from accept() or getaddrinfo() or similar functions. Parses it out and generates a CIDR structure based on it. Note that a in6_addr only contains a host address, so the netmask is initialized to all-1's (/128).
CIDR *
Returns a pointer to a populated CIDR containing the address in the passed-in struct in6_addr. The netmask is initialized to all-1's, and the protocol to IPv6 (though it may contain an IPv4-mapped address). Use cidr_free() to free the structure when you're finished with it. Returns NULL on error.
Note:
cidr_from_inaddr() can also fail and set errno for any of the reasons listed for cidr_alloc() .
Takes in a netblock description as a human-readable string, and creates a CIDR structure from it.
This is probably the most intricate function in the library. It accepts addresses in "address/mask" format. 'address' is an IP address in valid written form. For IPv4, it's 1 through 4 period-separated pieces, expressed in octal, hex, or decimal, with the last octet being treated as an 8, 16, 24, or 32-bit quantity depending on whether there are 4, 3, 2, or 1 pieces given (respectively). Of course, you're nuts for using that flexibility. For IPv6, it's nice and simple; 8 colon-separated double-octets, excepting that the last 4 octets can be expressed as a 4-piece dotted-decimal, like an IPv4 address (the full flexibility of the IPv4 parsing engine is not available, however; intentionally, though that may change if necessary). 'mask' can be either a prefix length (/0-/32 for IPv4, /0-/128 for IPv6), or a netmask written in the standard form for the address family.
IPv6 addresses can be specified in fully expanded form, or with ::-style contraction. IPv4-mapped IPv6 addresses (::ffff:a.b.c.d), will be treated as IPv6 addresses. The mask can be left off, in which case addresses are treated as host addresses (/32 or /128, depending on address family).
Also, cidr_from_str() will parse DNS PTR-record-style address formats. That is, representations like "<IP_ADDRESS>.in-addr.arpa" for IPv4, and an extremely long and annoying form ending in .ip6.arpa for IPv6. cidr_from_str() also understands the deprecated RFC1886 form of IPv6 PTR records, which ends in .ip6.int, though cidr_to_str() will only generate the current RFC3152-style .ip6.arpa version. Note also that while cidr_to_str() treats all addresses as host addresses when building the PTR string (ignoring the netmask), cidr_from_str() will fill in the netmask bits as appropriate for the string given; any octets (or half-octets, in the IPv6 form) that are left off the beginning will have their netmask bits set to 0.
It's not the intention of the author that this function necessarily be able to decipher any possible address format. However, the capabilities given should parse any rational address specification, and many irrational ones (like hex/oct and collapsed v4 addresses). The intention is rather to support the ways the addresses and netmasks are commonly written and read, so that a human-readable form can quickly be transformed into a format that libcidr can then use in its various ways, whether through comparing addresses with functions like cidr_contains() , or generating references and stats about a netblock with functions like cidr_addr_broadcast() and cidr_numhost() , or simply spitting it out in different human-readable forms with cidr_to_str() .
CIDR *
Returns a pointer to a populated CIDR describing (hopefully) the block you talked about in the string. Use cidr_free() to free the structure when you're finished with it. Returns NULL on error.
Note:
cidr_from_str() can also fail and set errno for any of the reasons listed for cidr_alloc() or cidr_get_pflen() .
Return the address bits which compose the address. This should be used in preference to simply referencing inside the CIDR manually in external code, since the structure might change on you.
Generally, if you think you need to call this, you should probably rethink what you're doing. Most of the time, one of the formatted outputs from cidr_to_str() or one of the manipulation functions like cidr_addr_hostmin() is what you want. Still, there are times when you're interesting in manipulating the address by yourself as a bunch of binary bits (the cidrcalc example program does this), so this function should be used instead of groping around in the structure manually.
uint8_t *
Returns a pointer to an 16-element array of uint8_t's representing the address. This array must be free() 'd when you're through with it. Returns NULL on error.
Return the netmask bits which of the given netblock. This should be used in preference to simply referencing inside the CIDR manually in external code, since the structure might change on you.
See further notes about the desirability of using this function above in the notes for cidr_get_addr() .
uint8_t *
Returns a pointer to an 16-element array of uint8_t's representing the netmask. This array must be free() 'd when you're through with it. Returns NULL on error.
Poke around the netmask of the passed-in CIDR structure and determine how many bits there are in the netmask, as appropriate to the address family.
int
Returns the number of network bits in the netmask (0-32 for IPv4, 0-128 for IPv6). Returns -1 on error.
Returns the protocol family of an address using one of the defined constants. The current choices are CIDR_IPV4 and CIDR_IPV6.
int
Returns the address family of the given netblock.
An IPv6 address may be in the network range reserved for IPv4-mapped addresses. This function will tell you whether it is or not. Note that an IPv4 CIDR is NOT considered an IPv4-mapped address, and so will return failure.
int
Returns 0 if the address is an IPv4-mapped IPv6 address. Returns -1 otherwise.
Take in a netblock, and derive the two netblocks which it divides up into. Return them in an array.
CIDR **
Returns a 2-element array of CIDR structs, containing the two subnets of addr. Each of the elements should be cleaned up with cidr_free() , and the array itself then cleaned up with free() . Returns NULL on failure.
Note:
cidr_net_subnets() can also fail and set errno for any of the reasons listed for cidr_addr_network() or cidr_dup() .
Take in a netblock, and derive the parent netblock in which it fits.
CIDR *
Returns a CIDR struct defining the parent network of addr. Clean this up with cidr_free() when you're finished with it. Returns NULL on failure.
Note:
cidr_net_supernet() can also fail and set errno for any of the reasons listed for cidr_dup() .
Determine the total number of addresses in a netblock (including the network and broadcast addresses).
This function returns a pointer to a pre-formatted string because we're potentially returning a value up to 2**128. I don't feel like trying to portably do 128-bit arithmetic. Do you?
const char *
Returns a pointer to a string containing the number of addresses in the netblock. Note that this is a static string; it should not be overwritten, and doesn't need to be free() 'd. Make a copy if you want to manipulate it. Returns NULL on error.
Note:
cidr_numaddr() can also also fail and set errno for any of the reasons listed for cidr_numaddr_pflen() .
Determine the total number of addresses in a netblock with the given prefix length (including the network and broadcast addresses).
Note that this takes an IPv6 prefix length; that is, 0-128. If you're interested in an IPv4 address with a given prefix length, add 96 to it when you call this function.
See the note in cidr_numaddr() for why we're returning a string and not a number.
const char *
Returns a pointer to a string containing the number of addresses in the netblock. Note that this is a static string; it should not be overwritten, and doesn't need to be free() 'd. Make a copy if you want to manipulate it. Returns NULL on error.
Determine the total number of host addresses in a netblock (excluding the network and broadcast addresses).
See the note in cidr_numaddr() for why we're returning a string and not a number.
const char *
Returns a pointer to a string containing the number of host addresses in the netblock. Note that this is a static string; it should not be overwritten, and doesn't need to be free() 'd. Make a copy if you want to manipulate it. Returns NULL on error.
Note:
cidr_numhost() can also also fail and set errno for any of the reasons listed for cidr_numhost_pflen() .
Determine the total number of host addresses in a netblock with the given prefix length (excluding the network and broadcast addresses).
Note that this takes an IPv6 prefix length; that is, 0-128. If you're interested in an IPv4 address with a given prefix length, add 96 to it when you call this function.
See the note in cidr_numaddr() for why we're returning a string and not a number.
const char *
Returns a pointer to a string containing the number of host addresses in the netblock. Note that this is a static string; it should not be overwritten, and doesn't need to be free() 'd. Make a copy if you want to manipulate it. Returns NULL on error.
Takes in a CIDR and creates a struct in_addr from it. This struct can then be used in connect() or similar network-related functions. If the users passes in a struct in_addr, it will be filled in. Otherwise, one will be allocated and returned.
struct in_addr *
Returns a pointer to the filled-in struct in_addr. If the user passed one in, this will just point to the same place and can profitably be ignored. If the user passed in NULL, this will point to the struct in_addr we allocated, which should be free() 'd by the user when they're finished with it. Returns NULL on error.
Takes in a CIDR and creates a struct in6_addr from it. This struct can then be used in connect() or similar network-related functions. If the users passes in a struct in6_addr, it will be filled in. Otherwise, one will be allocated and returned.
struct in6_addr *
Returns a pointer to the filled-in struct in6_addr. If the user passed one in, this will just point to the same place and can profitably be ignored. If the user passed in NULL, this will point to the struct in6_addr we allocated, which should be free() 'd by the user when they're finished with it. Returns NULL on error.
Takes in a CIDR structure, and generates up a human-readable string describing the netblock. This function has a lot of flexibility, depending on the flags passed to it. The default output is "address/pflen" form, with the address in a reasonably compact form, and the prefix length given numerically. Flags alter the output in various ways, and are set as bitmasks, so they can be combined however you wish. They can be used in any combination that makes sense, and a large number of combinations that don't.
The current flags are:
CIDR_NOFLAGS: A stand-in for when you just want the default
output
CIDR_NOCOMPACT: Don't do ::-style IPv6 compaction
CIDR_VERBOSE: Show leading 0's in octets [v6 only]
CIDR_USEV6: Use IPv4-mapped address form for IPv4 addresses
(::ffff:a.b.c.d)
CIDR_USEV4COMPAT: Use IPv4-compat form (::a.b.c.d) instead of
IPv4-mapped form (only meaningful in combination with
CIDR_USEV6)
CIDR_NETMASK: Return a netmask in standard form after the
slash, instead of the prefix length. Note that the form of the
netmask can thus be altered by the various flags that alter
how the address is displayed.
CIDR_ONLYADDR: Show only the address, without the
prefix/netmask
CIDR_ONLYPFLEN: Show only the prefix length (or netmask, when
combined with CIDR_NETMASK), without the address.
CIDR_WILDCARD: Show a Cisco-style wildcard mask instead of the
netmask (only meaningful in combination with CIDR_NETMASK)
CIDR_FORCEV6: Forces treating the CIDR as an IPv6 address, no matter what it
really is. This doesn't do any conversion or translation; just
treats the raw data as if it were IPv6.
CIDR_FORCEV4: Forces treating the CIDR as an IPv4 address, no matter what it
really is. This doesn't do any conversion or translation; just
treats the raw data as if it were IPv4.
CIDR_REVERSE: Generates a .in-addr.arpa or .ip6.arpa-style PTR
record name for the given block. Note that this always treats
it solely as an address; the netmask is ignored. See some
notes in cidr_from_str() for
details of the asymmetric treatment of this form of address
representation relating to the netmask.
Many combinations can give somewhat surprising results, but they should allow any of a host of manipulations to output just the data you might be interested in. The "mkstr" test program in the source tree is extremely useful for manual testing of the various flags to see visually what they do, and is a lot quicker than trying to code them all to test it out. Use it to your advantage.
char *
Returns a pointer to a string containing the representation of the network. Be sure to free() it when you're finished.
Note:
cidr_to_str() can also fail and set errno for any of the reasons listed for cidr_alloc() or cidr_get_pflen() .
Returns a static string describing the library release version.
const char *
Returns a pointer to a static string describing the library version number. It shouldn't be overwritten or free() 'd.


SQL Injection
What is SQL?
SQL is short for Structured Query Language. It is a programming language for querying (fancy word for accessing) and managing databases. SQL is has its own syntax and different database systems some of which include Microsoft Access, SQLite, MySQL, and PostgreSQL. Each of these databases have individual variations of SQL. SQL is essential to web applications that require data storing/access.
SQL Injection
SQL injection primarily involves leaving "windows" open in code for hackers to retrieve data they shouldn't have access to. in the context of Ruby, when strings were not properly closed off with quote marks it led to errors. However, when working with SQL these strings are the open windows in website's databases. The hacks occur whenever the program or website receives input from the user without sanitizing it. For example, if we had a website connected to a database of customers' credit card information the hacker could inject his own SQL statement into the query and take the information he or she wanted. In the figure below a user would input between the quotes in the first line to enter information.
In lines 3-4 a hacker with malicious intentions has inserted his own query into the field and is now taking all information in the customer_credit_card_info table. To sanitize this code we can add escaping backslashes before every first quote mark from the user like in lines 6-7. Now, the query the hacker has inputted returns nothing.
The SQLite3 gem for Ruby has a method for handling the quoted input by using '?' placeholder in the query and passing extra values to the 'execute' method. The number of placeholders must match the number of arguments. This prevents a hacker from adding his own number of arguments in the query.
There are many other methods to prevent SQL injection some of which include the use of Prepared Statements or parametized queries, use of stored procedures, escaping all user supplied input which we discussed above, enforcing least privilege, and white list input validation. Using prepared statements are simple to write and understand. Parametizing queries require SQL code to be defined first and then pass each parameter into the query later. This allows the database to differientiate between code and data regardless od user input. Prepared statements prevent the hacker from changing the intention of the query. For example, if a hacker wanted to input in 'Rick' or '1'='1 the parametized query would deny the hackers' malicious intention and would literally look for the string or for '1'='1. For the sake of blog length you can find the other methods explained in great detail in the links provided below.
For additional information on SQL injection and its prevention methods check these websites out!
Posts
-
The Post DBC Experience
Mixed Emotions
DBC was an awesome, maybe one of a kind experience. I pushed through all 4 phases with the mantids, or the improper plural...
-
How to Ask for Help
How to Ask Good Questions
Experienced Questioning
I don't always ask questions online but when I do I try to be as specific as possible...
-
Ruby on Rails
Rails
Ruby and Rails are not the same thing. Ruby is the programming language. Rails is a Rubygem or package library which is installed via...
-
Resolving Conflicts
A Conflict I Experienced
Honestly, I cannot remember a conflict I've experienced off the top of my head that would be exciting to read or...
- My Thinking Ways How do I Think? I am a concrete sequential thinker which according to cgribben.com mean that I am persistent and product oriented. I am practical...
-
SQL Injection
What is SQL?
SQL is short for Structured Query Language. It is a programming language for querying (fancy word for accessing) and managing databases. SQL...
-
Affirmation and Stereotype Threat
My Values
Accomplishment, accountability, compassion, creativity, efficiency, family, friendships, and integrity area few values which come to mind when I recall the times in my...
-
Blocs, Procs, and Lambdas
Ruby Blocks, Procs, Lambdas
Blocks
A ruby block is the piece of code that is executed. This code can be executed using curly brackets {}...
-
Stereotype Threat
What is Stereotype Threat?
To put it simply, stereotype threat is the experience of not living or carrying out your full potential because of stereotypes....
-
A Pair of Minds
Pairing and Feedback
Pairing
Pairing isn't so bad. The peers are all nice and I haven't met someone who was disrespectful during the sessions. Despite...
-
A Little Ruby
A Snippet into Ruby Classes
When and Why Should I use classes?
One question which kept simmering in my head while working on this week's...
-
Ruby Cycle and Looping
Ruby:Enumberable#Cycle
The #cycle method uses a block for each element of an enumerable object (ranges, hash, or array) repeatedly for n times or endlessly if...
-
Today's Software Apps vs Law
Who Doesn’t Like App Efficiency?
Innovative technologies usually clash with old ways and methods. There are numerous apps out there which are constantly clashing with...
-
What is JS?
What is JavaScript and Why Should You Care?
Javascript(JS) is an object oriented computer programming language often found as a part of web browsers which...
-
CSS Positioning
Positioning in CSS
Elements on a website can be positioned behind, in front of, or next to by using CSS positioning properties: top, left, right,...
-
My Favorite Websites
My 3 Most Visited Websites
Newcelica.org
This is one of my favorite sites because I own a Celica. I do all...
-
Kitchen Vs Table
Kitchen Vs Table
DBC sounds like a buttkicker, a mental, emotional, and physical obstacle course. Honestly, it sounds like it would and should be overwhelming...


Detailed setup of a mini Django News App project with Bootstrap, AJAX, Celery and RabbitMQ
The Django project started in the news room. This article will offer detailed documentation of the setup process for a simple news application. This project was given as a takehome assignment for another Django position I am interview for. I won’t focus on any production considerations as this is only a demo project that is supposed to work locally.
For reference, the code is on this Github repository.
Requirements
This project included some interesting requirements that were outside of the scope of simple apps I have put together with Django. Two import ones were page caching and using celery to execute tasks asynchronously. I also set up a unit tests and functional tests and tested the core functionalities of the application. Here are some the basic requirements:
- Implement a news model with fields such as title, body, content, author, etc.
- Display published posts on a page styled with Bootstrap
- Implement and admin page that allows staff to create and publish posts
- Cache the public facing home page
- On the home page use jQuery to poll a URL for updates, and refresh the page if an update is found.
- Add a button on the public facing page that when pressed launches a celery task that send an email to the site admin.
Release Notes and code snippets
Here’s a quick description of the design decisions I made for the various specifications with code snippets:
Post Model
For the Post model I decided to use two DateTimeFields: updated
and timestamp
. timestamp
is the public-facing time that shows on each article. updated
is changed when a publish or unpublish action is taken on a Post.
When a POST
request is made to the toggle_publish
view, three things happen:
-
The Post’s
published
field is toggled and the Post’supdated
field is set to the current time. -
The only record in
LastUpdate
is updated. This model only contains aDateTimeField
also calledupdated
. -
The cache is cleared, clearing any pages cached from the
home
view.
Home Page
For the public facing home page, I return a list of Posts where published
is set to True
and also return a UNIX time epoch of the Post with the most recent updated
field.
views.py
@cache_page(None)
def home(request):
"""
This is the public view that displays only published posts.
The view also returns a UNIX timestamp of the most recently updated post.
This timestamp is compared with the `LastUpdate` value to determine when the page should be refreshed.
Every 5 seconds, the `latest` timestamp is compared with the `LastUpdate` timestamp.
If `LastUpdate` is greater that `latest`, this implies that a Post has either been published or unpublished.
"""
posts = Post.objects.filter(published=True)
latest = 0
if posts:
latest = Post.objects.latest('updated').unix_time()
return render(request, 'posts/home.html', {'posts':posts, 'latest':latest})
AJAX poll on home page
I use an AJAX poll that returns a JSON response containing the updated
field of LastUpdate
as a UNIX time epoch called latest
. I compare this UNIX time epoch with the the UNIX time epoch returned with context data in home
. If the latest
value is greater than the the UNIX time stamp of the most recently updated article, then the page is reloaded. At this point, the cache will have been cleared by toggle_publish
, and the new Posts are displayed.
home.html (AJAX poll)
<script>
console.log("working")
poll = function() {
$.ajax({
url: '/refresh',
dataType: 'json',
type: 'get',
success: function(data) {
var latest = parseInt(data.latest)
var latest_local = parseInt($("#last").attr('data'))
if (latest > latest_local + 2){
location.reload()
}
},
error: function() {
console.log('The refresh poll was not successful');
}
});
},
pollInterval = setInterval(function() {
poll();
}, 5000);
</script>
views.py (the view that the AJAX poll requests; return JSON)
def refresh(request):
"""
This is the URL that is polled by the public-facing page.
It returns a UNIX timestamp of the last time an article was published or unpublished.
This timestamp comes from the `LastUpdated`, a table that stores and updates only one row with one datetime column.
Publishing and unpublishing are the only two actions that clear the cached homepage.
When the returned UNIX timestamp is greater than the UNIX timestamp of the most recently updated article,
The page is refreshed with `location.reload()`.
"""
t, created = LastUpdate.objects.get_or_create(id=1)
if created:
t.save()
t = t.unix_time()
else:
t = t.unix_time()
latest = int(t) - 2
return JsonResponse({'latest':int(latest)})
Email admin through a celery task
The email feature is functional, but the button returns a JSON response that says “successful” if the message was sent to celery. My plan was to make another AJAX call and then updated the Email Admin
link to say Your email was sent.
if it the task was sent the messaging service.
For details on how celery can be set up with a Django project, I reference on of my favorite Django blogs, simpleisbetterthancomplex.com. This article shows how to set up celery in a Django project and my set up almost exactly mirrors this setup, but my celery task simply sends an email.
Admin Page
The admin page contains a list of all articles. Each article contains a link to manage publish settings. This calls the toggle_publish
page that displays the selected article and contains a button that says Publish
or Unpublish
depending on the value of the Post’s published
value.
Cache
For caching I chose the memcached backend. Other options included using file caching and database caching, but this seemed to be the simplest approach. I used a decorator function to cache the results of the home
view.
Here are some additional notes on how I used caching in this project:
- To cache a page from the
home
view, I used a decorator:from django.views.decorators.cache import cache_page
:
@cache_page(None)
def home(request):
[...]
-
We pass the argument of
None
so that the page cache does not expire; we will manually clear the cache when a staff member publishes an article. -
The first time we access the
home
view, we will see our print statement, in subsequent requests, the cached page will be used and we will not see the print statement.
In order for caching to work we need to add the following to settings.py
:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '<IP_ADDRESS>:11211',
}
}
Next, we need to install the following packages:
(virtualenv) $ pip install memcache
# pacman -S memcached
# systemctl start memcached
# systemctl enable memcached
Clearing the cache
To clear the cache, we can simply do the following in a view:
from django.core.cache import cache
@login_required
def toggle_publish(request,id):
instance = get_object_or_404(Post, id=id)
if request.method=="POST":
instance.published = not instance.published
instance.save()
t = LastUpdate.objects.all().first()
t.updated = instance.updated
t.save()
cache.clear()
return redirect('posts:home')
context = {'post':instance}
return render(request, 'posts/publish.html', context)
cache.clear()
clears the cache, and the home
view is regenerated from the Queryset and template rather the being served directly from the cache. This newly generated page is then saved to the cache and used on subsequent calls to home
until the cache is cleared again.
Basic setup
Here are the first steps need to set up the project correctly:
First, let’s start with creating a virtual environment:
$ virtualenv -p python3 virtualenv
Next, let’s activate the virtual environment with:
$ source virtualenv/bin/activate
Next, let’s install django
and selenium
:
(virtualenv) $ pip install django selenium
Next, let’s start our app:
(virtualenv) $ django-admin.py startproject news .
The .
will start the project in the current environment. Let’s take a look at the directory structure:
(virtualenv) $ tree -L 2
$ tree -L 2
.
├── manage.py
├── news
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── virtualenv
├── bin
├── include
├── lib
├── pip-selfcheck.json
└── selenium
At this point, we can start the local server:
(virtualenv) $ python manage.py runserver
Performing system checks...
System check identified no issues (0 silenced).
You have 14 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
February 10, 2018 - 02:16:47
Django version 2.0.2, using settings 'news.settings'
Starting development server at http://<IP_ADDRESS>:8000/
Quit the server with CONTROL-C.
Now we should see the new Django 2 startup screen in our browser if we navigate to http://<IP_ADDRESS>:8000/:
Testing
I had a few difficulties setting up selenium testing with this projects. Here the functional_tests.py
file that is hopefully configured correctly:
functional_tests.py
from selenium import webdriver
from django.conf import settings
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'news.settings')
from django.test import LiveServerTestCase
import unittest
import time
import factory
from django.contrib.auth import get_user_model
from selenium import webdriver
User = get_user_model()
class UserFactory(factory.DjangoModelFactory):
"""This class sets up a staff user that we can use for testing using factory"""
class Meta:
model = User
email =<EMAIL_ADDRESS>username = 'brian1'
password = factory.PostGenerationMethodCall('set_password', 'qwer1234')
is_superuser = True
is_staff = True
is_active = True
class NewsAppTest(LiveServerTestCase):
"""Main Tests"""
def setUp(self):
self.browser = webdriver.Firefox()
self.domain = 'http://<IP_ADDRESS>:8081'
self.user = UserFactory.create()
def tearDown(self):
self.browser.quit()
def test_page_title_is_correct(self):
self.browser.get(self.domain)
self.assertIn('Django News', self.browser.title)
def test_staff_can_create_and_publish_article(self):
"""
Tests the core functionality of a staff member loging in, creating an article, then publishing that article
"""
# staff logs into admin page
self.browser.get(self.domain+"/admin")
self.browser.find_element_by_id('id_username').send_keys('brian1')
self.browser.find_element_by_id('id_password').send_keys('qwer1234')
self.browser.find_element_by_class_name('submit-row').click()
# navigate to homepage
self.browser.get(self.domain)
time.sleep(2)
# navigate to new article page and write sample article
self.browser.find_element_by_id('new-article').click()
html = str(self.browser.page_source.encode('utf-8'))
self.assertIn('Write your Django News article here', html)
self.browser.find_element_by_id('id_title').send_keys('testing with selenium')
self.browser.find_element_by_id('id_content').send_keys('about testing with selenium')
self.browser.find_element_by_id('id_submit').click()
html = str(self.browser.page_source.encode('utf-8'))
self.assertIn('publish settings', html)
# go back to home page and check that the article is not displayed
self.browser.get(self.domain)
html = str(self.browser.page_source.encode('utf-8'))
self.assertNotIn('testing with selenium', html)
self.browser.back()
self.browser.find_element_by_id('toggle-publish').click()
html = str(self.browser.page_source.encode('utf-8'))
self.assertIn('testing with selenium', html)
def test_public_page_reloads_when_article_is_published(self):
browser2 = webdriver.Firefox()
browser2.get(self.domain)
html = browser2.page_source
self.test_staff_can_create_and_publish_article()
time.sleep(2)
browser2.get(self.domain)
html_after_publish = browser2.page_source
self.assertNotEqual(html, html_after_publish)
browser2.quit()
if __name__ == "__main__":
unittest.main(warnings="ignore")
I used the package called factory_boy
to setup create a user that I could use in my test. This project didn’t include a staff registration page, so to test regular staff functionality I used factory
to create a dummy user that can login and perform tasks.
For the full repo, please find it on my github account: https://github.com/briancaffey/django-news-app.


Home
The App
The App
The App
Start 📷
Stop ✋
Video stream not available.
Speech Recognition
Microsoft Cognitive Services
Subscription
:
Laguage:
Chinese - CN
English - GB
English - US
French - FR
German - DE
Italian - IT
Spanish - ES
Status:
Output
Place Data and outpt here.


|
Frappy Birds
|
Models Game State. More...
#include <main.h>
Data Fields | |
| Bird * | birdy |
| queue * | que |
| Coin * | coin |
| PlayerLevel * | playerLevel |
| bool | alive |
| int | difficulty |
| int | frameCount |
| int | score |
| int | pipeGap |
| Score | highScore |
| int | pipeDistance |
| Score | scores [4] |
| int | birdType |
Models Game State.
Stores all game information regarding the current state of the game.
| bool GameInfo::alive |
Boolean check to see if the game is still playing
| Bird* GameInfo::birdy |
Pointer to bird in play
| Coin* GameInfo::coin |
Pointer to coin in play
| int GameInfo::difficulty |
Difficulty rating (0-2)
| int GameInfo::frameCount |
Counter for frames
| Score GameInfo::highScore |
Highest score achieved in game state
| int GameInfo::pipeDistance |
Distance between concurrent pipes
| int GameInfo::pipeGap |
Distance between top and bottom pipe
| PlayerLevel* GameInfo::playerLevel |
Pointer to player level in play
| queue* GameInfo::que |
Pointer to queue containing all pipes
| int GameInfo::score |
Current score of the game
| Score GameInfo::scores[4] |
Saves n most current scores


A place where all are welcome.
Be Creative. Be Productive. Have Fun.
Fast Wifi
Learn More
Espresso Bar
Work Areas
Activities
Unlimited Access
For a single person
dollars per month
For up to five people
For up to ten people
Office Phone:<PHONE_NUMBER>
Email: office@imagine.studios


[ht::head {IMDV Introduction} ]
:navtop
+callout-info
Here are the set of steps to create a simple map.
-callout
:heading Create a New Map
From the entry menu choose "Pick a Type...".
[ht::screenshot images/pickatype.png {}]
Under GIS Data select "Integrated Map Data":
[ht::screenshot images/new.png {New Entry}]
Enter a name for your map. You can ignore the file. Enter some description.
Note: the description is wiki text.
[ht::screenshot images/newform.png {New Map Form} ]
Once created you will have the initial display below.
[ht::screenshot images/imdv1.png {Initial Display}]
:br
:heading Basic Editing
Select the New menu to see the different map glyph types that can be added.
You can add Groups, basic shapes - Marker, Label, Lines, Box, etc., Map files,
remote Map Servers, Images and other RAMADDA entries.
[ht::screenshot images/newmenu.png {New Menu}]
Selecting a shape click and/or click-drag in the map to create the shape.
Once something is created in the map a legend is shown on the left.
Here we have created a Group called "Some Group", a Marker, a Box and a Freehand glyph.
The glyphs in the legend can be dragged and dropped to reorder. You can also
drag a glyph onto a Group to add the glyph to the group.
[ht::screenshot images/imdv2.png]
:heading Properties Dialog
Clicking on the toggle arrow ()
shows more details for the glyph. The link
takes brings up an edit window for that glyph. This allows you to specify
the drawing style and other properties.
:p
The main Properties tab allows you to change the name of the glyph,
toggle the visibility and specify what zoom levels this glyph is
visible in. This allows you to, for example, specify that when the
map is zoomed out the glyph won't be shown.
The popup text is the text shown when the user clicks on the glyph.
The legend text is just extra text shown in the legend.
[ht::screenshot images/properties_properties.png]
The Flags tab allows you to specify a number of extra flags or properties
for this glyph. For example, below the showButtons and showMeasures are both set to
false. With showButtons the button links in the legend won't be shown for non-logged in users.
The showMeasure=false says to not show the distance and dimensions in the legend.
[ht::screenshot images/properties_flags.png]
The Style tab provides settings that control the drawing style of the glyph.
These settings can vary depending on the type of the glyph.
The Active button, if set, will apply the style to the glyph when it is changed in the form.
[ht::screenshot images/properties_style.png]
The style tab for the Group will contain all possible styles.
Clicking on the icon for any one style will apply
that style to all of the contained glyphs within the group.
[ht::screenshot images/properties_style_group.png]
:heading File Menu
The File menu allows you to Save the map. The map is saved as a JSON file associated with
the IMDV entry. This file can be downloaded and added to make a new IMDV entry.
:p
Other actions include:
* Import - Select another IMDV entry to import its map from
* List Features - Shows an alternative to the legend
* Clear Commands - clear out the current command (e.g, New Marker)
* Set Default Style - Show the Style dialog that is used for any new glyphs
[ht::screenshot images/filemenu.png]
The Properties link brings up the Properties dialog for the IMDV map.
You can:
* Show Opacity Slider - for any images this changes the opacity
* Show Graticules - show lat/lon lines
* Show Mouse Position - show lat/lon of mouse
* Show Address - Show an input that allows for searching for addresses
* Legend Position - Select where the legend should be shown
* Show Base Map Select - show a menu in the legend to set the base map
* Header/Footer - add wiki text to show above and below the map
[ht::screenshot images/properties.png]
:heading Edit Menu
The Edit Menu allows you to select glyphs, cut/copy/paste, move/reshape/rotate, etc.
[ht::screenshot images/editmenu.png]


Danielle Byrne
About
(current)
Portfolio
Contact
Contact Me
Contact Phone Number :<PHONE_NUMBER>
<EMAIL_ADDRESS>LinkedIn Profile
GitHub
View my Resume


---
# You don't need to edit this file, it's empty on purpose.
# Edit theme's home layout instead if you wanna make some changes
# See: https://jekyllrb.com/docs/themes/#overriding-theme-defaults
layout: page
---
{% for post in paginator.posts %}
{{ post.title }}
{{ post.excerpt }}
Read More


Before Change
// Add the root as first group
self.allGroupPaths.append("/")
// The root group is not an end group
self.allGroupEnds["/"] = False
// The first root group has not been added yet
self.firstRootGroup = False
// The root name is / . it can be changed if addGroupInit is called
self.parentGroupName = b"/"
After Change
self.firstRootGroup = False
// The root name is / . it can be changed if addGroupInit is called
self.parentGroupName = b"/"
self.h5FileW.create_dataset("allGroupPaths", shape=(1,), dtype=variableLengthStr, data=self.allGroupPaths, maxshape=(None,))
self.h5FileW.create_dataset("allGroupEnds", shape=(1,), dtype=bool, data=self.allGroupEnds, maxshape=(None,))
def __len__(self):