PHP's new hashtable implementation
About three years ago I wrote an article analyzing the memory usage of arrays in PHP 5. As part of the work on the upcoming PHP 7, large parts of the Zend Engine have been rewritten with a focus on smaller data structures requiring fewer allocations. In this article I will provide an overview of the new hashtable implementation and show why it is more efficient than the previous implementation.
To measure memory utilization I am using the following script, which tests the creation of an array with 100000 distinct integers:
$startMemory = memory_get_usage();
$array = range(1, 100000);
echo memory_get_usage() - $startMemory, " bytes\n";
The following table shows the results using PHP 5.6 and PHP 7 on 32bit and 64bit systems:
| 32 bit | 64 bit
------------------------------
PHP 5.6 | 7.37 MiB | 13.97 MiB
------------------------------
PHP 7.0 | 3.00 MiB | 4.00 MiB
In other words, arrays in PHP 7 use about 2.5 times less memory on 32bit and 3.5 on 64bit (LP64), which is quite impressive.
Introduction to hashtables
In essence PHP’s arrays are ordered dictionaries, i.e. they represent an ordered list of key/value pairs, where the key/value mapping is implemented using a hashtable.
A Hashtable is an ubiquitous data structure, which essentially solves the problem that computers can only directly represent continuous integer-indexed arrays, whereas programmers often want to use strings or other complex types as keys.
The concept behind a hashtable is very simple: The string key is run through a hashing function, which returns an integer. This integer is then used as an index into a “normal” array. The problem is that two different strings can result in the same hash, as the number of possible strings is virtually infinite while the hash is limited by the integer size. As such hashtables need to implement some kind of collision resolution mechanism.
There are two primary approaches to collision resolution: Open addressing, where elements will be stored at a different index if a collision occurs, and chaining, where all elements hashing to the same index are stored in a linked list. PHP uses the latter mechanism.
Typically hashtables are not explicitly ordered: The order in which elements are stored in the underlying array depends on the hashing function and will be fairly random. But this behavior is not consistent with the semantics of PHP arrays: If you iterate over a PHP array you will get back the elements in the exact order in which they were inserted. This means that PHP’s hashtable implementation has to support an additional mechanism for remembering the order of array elements.
The old hashtable implementation
I’ll only provide a short overview of the old hashtable implementation here, for a more comprehensive explanation please see the hashtable chapter of the PHP Internals Book. The following graphic is a very high-level view of how a PHP 5 hashtable looks like:
The elements in the “collision resolution” chain are referred to as “buckets”. Every bucket is individually allocated. What the image glosses over are the actual values stored in these buckets (only the keys are shown here). Values are stored in separately allocated zval structures, which are 16 bytes (32bit) or 24 bytes (64bit) large.
Another thing the image does not show is that the collision resolution list is actually a doubly linked list (which
simplifies deletion of elements). Next to the collision resolution list, there is another doubly linked list storing the
order of the array elements. For an array containing the keys "a", "b", "c"
in this order, this list could look as
follows:
So why was the old hashtable structure so inefficient, both in terms of memory usage and performance? There are a number of primary factors:
- Buckets require separate allocations. Allocations are slow and additionally require 8 / 16 bytes of allocation overhead. Separate allocations also means that the buckets will be more spread out in memory and as such reduce cache efficiency.
- Zvals also require separate allocations. Again this is slow and incurs allocation header overhead. Furthermore this requires us to store a pointer to a zval in each bucket. Because the old implementation was overly generic it actually needed not just one, but two pointers for this.
- The two doubly linked lists require a total of four pointers per bucket. This alone takes up 16 / 32 bytes.. Furthermore traversing linked lists is a very cache-unfriendly operation.
The new hashtable implementation tries to solve (or at least ameliorate) all of these problems.
The new zval implementation
Before getting to the actual hashtable, I’d like to take a quick look at the new zval structure and highlight how it
differs from the old one. The zval
struct is defined as follows:
struct _zval_struct {
zend_value value;
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar type,
zend_uchar type_flags,
zend_uchar const_flags,
zend_uchar reserved)
} v;
uint32_t type_info;
} u1;
union {
uint32_t var_flags;
uint32_t next; /* hash collision chain */
uint32_t cache_slot; /* literal cache slot */
uint32_t lineno; /* line number (for ast nodes) */
} u2;
};
You can safely ignore the ZEND_ENDIAN_LOHI_4
macro in this definition - it is only present to ensure a predictable
memory layout across machines with different endianness.
The zval structure has three parts: The first member is the value
. The zend_value
union is 8 bytes large and can
store different kinds of values, including integers, strings, arrays, etc. What is actually stored in there depend on
the zval type.
The second part is the 4 byte type_info
, which consists of the actual type
(like IS_STRING
or IS_ARRAY
), as well
as a number of additional flags providing information about this type. E.g. if the zval is storing an object, then the
type flags would say that it is a non-constant, refcounted, garbage-collectible, non-copying type.
The last 4 bytes of the zval structure are normally unused (it’s really just explicit padding, which the compiler would introduce automatically otherwise). However in special contexts this space is used to store some extra information. E.g. AST nodes use it to store a line number, VM constants use it to store a cache slot index and hashtables use it to store the next element in the collision resolution chain - that last part will be important to us.
If you compare this to the previous zval implementation, one difference particularly stands out: The new zval structure no longer stores a refcount. The reason behind this, is that the zvals themselves are no longer individually allocated. Instead the zval is directly embedded into whatever is storing it (e.g. a hashtable bucket).
While the zvals themselves no longer use refcounting, complex data types like strings, arrays, objects and resources still use them. Effectively the new zval design has pushed out the refcount (and information for the cycle-collector) from the zval to the array/object/etc. There are a number of advantages to this approach, some of them listed in the following:
- Zvals storing simple values (like booleans, integers or floats) no longer require any allocations. So this saves the allocation header overhead and improves performance by avoiding unnecessary allocs and frees and improving cache locality.
- Zvals storing simple values don’t need to store a refcount and GC root buffer.
- We avoid double refcounting. E.g. previously objects both used the zval refcount and an additional object refcount, which was necessary to support by-object passing semantics.
- As all complex values now embed a refcount, they can be shared independently of the zval mechanism. In particular it is now also possible to share strings. This is important to the hashtable implementation, as it no longer needs to copy non-interned string keys.
The new hashtable implementation
With all the preliminaries behind us, we can finally look at the new hashtable implementation used by PHP 7. Lets start by looking at the bucket structure:
typedef struct _Bucket {
zend_ulong h;
zend_string *key;
zval val;
} Bucket;
A bucket is an entry in the hashtable. It contains pretty much what you would expect: A hash h
, a string key key
and
a zval value val
. Integer keys are stored in h
(the key and hash are identical in this case), in which case the
key
member will be NULL
.
As you can see the zval is directly embedded in the bucket structure, so it doesn’t have to be allocated separately and we don’t have to pay for allocation overhead.
The main hashtable structure is more interesting:
typedef struct _HashTable {
uint32_t nTableSize;
uint32_t nTableMask;
uint32_t nNumUsed;
uint32_t nNumOfElements;
zend_long nNextFreeElement;
Bucket *arData;
uint32_t *arHash;
dtor_func_t pDestructor;
uint32_t nInternalPointer;
union {
struct {
ZEND_ENDIAN_LOHI_3(
zend_uchar flags,
zend_uchar nApplyCount,
uint16_t reserve)
} v;
uint32_t flags;
} u;
} HashTable;
The buckets (= array elements) are stored in the arData
array. This array is allocated in powers of two, with the
size being stored in nTableSize
(the minimum value is 8). The actual number of stored elements is nNumOfElements
.
Note that this array directly contains the Bucket
structures. Previously we used an array of pointers to separately
allocated buckets, which means that we needed more alloc/frees, had to pay allocation overhead and also had to pay for
the extra pointer.
Order of elements
The arData
array stores the elements in order of insertion. So the first array element will be stored in arData[0]
,
the second in arData[1]
etc. This does not in any way depend on the used key, only the order of insertion matters
here.
So if you store five elements in the hashtable, slots arData[0]
to arData[4]
will be used and the next free slot is
arData[5]
. We remember this number in nNumUsed
. You may wonder: Why do we store this separately, isn’t it the same
as nNumOfElements
?
It is, but only as long as only insertion operations are performed. If an element is deleted from a hashtable, we
obviously don’t want to move all elements in arData
that occur after the deleted element in order to have a continuous
array again. Instead we simply mark the deleted value with an IS_UNDEF
zval type.
As an example, consider the following code:
$array = [
'foo' => 0,
'bar' => 1,
0 => 2,
'xyz' => 3,
2 => 4
];
unset($array[0]);
unset($array['xyz']);
This will result in the following arData
structure:
nTableSize = 8
nNumOfElements = 3
nNumUsed = 5
[0]: key="foo", val=int(0)
[1]: key="bar", val=int(1)
[2]: val=UNDEF
[3]: val=UNDEF
[4]: h=2, val=int(4)
[5]: NOT INITIALIZED
[6]: NOT INITIALIZED
[7]: NOT INITIALIZED
As you can see the first five arData
elements have been used, but elements at position 2 (key 0
) and 3 (key 'xyz'
)
have been replaced with an IS_UNDEF
tombstone, because they were unset
. These elements will just remain wasted
memory for now. However, once nNumUsed
reaches nTableSize
PHP will try compact the arData
array, by dropping any
UNDEF
entries that have been added along the way. Only if all buckets really contain a value the arData
will be
reallocated to twice the size.
The new way of maintaining array order has several advantages over the doubly linked list that was used in PHP 5.x. One obvious advantage is that we save two pointers per bucket, which corresponds to 8/16 bytes. Additionally it means that iterating an array looks roughly as follows:
uint32_t i;
for (i = 0; i < ht->nNumUsed; ++i) {
Bucket *b = &ht->arData[i];
if (Z_ISUNDEF(b->val)) continue;
// do stuff with bucket
}
This corresponds to a linear scan of memory, which is much more cache-efficient than a linked list traversal (where you go back and forth between relatively random memory addresses).
One problem with the current implementation is that arData
never shrinks (unless explicitly told to). So if you
create an array with a few million elements and remove them afterwards, the array will still take a lot of memory. We
should probably half the arData
size if utilization falls below a certain level.
Hashtable lookup
Until now we have only discussed how PHP arrays represent order. The actual hashtable lookup uses the second arHash
array, which consists of uint32_t
values. The arHash
array has the same size (nTableSize
) as arData
and both
are actually allocated as one chunk of memory.
The hash returned from the hashing function (DJBX33A for string keys) is a 32-bit or 64-bit unsigned integer, which is
too large to directly use as an index into the hash array. We first need to adjust it to the table size using a modulus
operation. Instead of hash % ht->nTableSize
we use hash & (ht->nTableSize - 1)
, which is the same if the size is a
power of two, but doesn’t require expensive integer division. The value ht->nTableSize - 1
is stored in
ht->nTableMask
.
Next, we look up the index idx = ht->arHash[hash & ht->nTableMask]
in the hash array. This index corresponds to the
head of the collision resolution list. So ht->arData[idx]
is the first entry we have to examine. If the key stored
there matches the one we’re looking for, we’re done.
Otherwise we must continue to the next element in the collision resolution list. The index to this element is stored in
bucket->val.u2.next
, which are the normally unused last four bytes of the zval
structure that get a special meaning
in this context. We continue traversing this linked list (which uses indexes instead of pointers) until we either find
the right bucket or hit an INVALID_IDX
- which means that an element with the given key does not exist.
In code, the lookup mechanism looks like this:
zend_ulong h = zend_string_hash_val(key);
uint32_t idx = ht->arHash[h & ht->nTableMask];
while (idx != INVALID_IDX) {
Bucket *b = &ht->arData[idx];
if (b->h == h && zend_string_equals(b->key, key)) {
return b;
}
idx = Z_NEXT(b->val); // b->val.u2.next
}
return NULL;
Lets consider how this approach improves over the previous implementation: In PHP 5.x the collision resolution used a
doubly linked pointer list. Using uint32_t
indices instead of pointers is better, because they take half the size on
64bit systems. Additionally fitting in 4 bytes means that we can embed the “next” link into the unused zval slot, so we
essentially get it for free.
We also use a singly linked list now, there is no “prev” link anymore. The prev link is primarily useful for deleting elements, because you have to adjust the “next” link of the “prev” element when you perform a deletion. However, if the deletion happens by key, you already know the previous element as a result of traversing the collision resolution list.
The few cases where deletion occurs in some other context (e.g. “delete the element the iterator is currently at”) will have to traverse the collision list to find the previous element. But as this is a rather unimportant scenario, we prefer saving memory over saving a list traversal for that case.
Packed hashtables
PHP uses hashtables for all arrays. However in the rather common case of continuous, integer-indexed arrays (i.e. real arrays) the whole hashing thing doesn’t make much sense. This is why PHP 7 introduces the concept of “packed hashtables”.
In packed hashtables the arHash
array is NULL
and lookups will directly index into arData
. If you’re looking for
the key 5
then the element will be located at arData[5]
or it doesn’t exist at all. There is no need to traverse a
collision resolution list.
Note that even for integer indexed arrays PHP has to maintain order. The arrays [0 => 1, 1 => 2]
and
[1 => 2, 0 => 1]
are not the same. The packed hashtable optimization only works if keys are in ascending order. There
can be gaps in between them (the keys don’t have to be continuous), but they need to always increase. So if elements are
inserted into an array in a “wrong” order (e.g. in reverse) the packed hashtable optimization will not be used.
Note furthermore that packed hashtables still store a lot of useless information. For example we can determine the index
of a bucket based on its memory address, so bucket->h
is redundant. The value bucket->key
will always be NULL
, so
it’s just wasted memory as well.
We keep these useless values around so that buckets always have the same structure, independently of whether or not packing is used. This means that iteration can always use the same code. However we might switch to a “fully packed” structure in the future, where a pure zval array is used if possible.
Empty hashtables
Empty hashtables get a bit of special treating both in PHP 5.x and PHP 7. If you create an empty array []
chances are
pretty good that you won’t actually insert any elements into it. As such the arData
/arHash
arrays will only be
allocated when the first element is inserted into the hashtable.
To avoid checking for this special case in many places, a small trick is used: While the nTableSize
is set to either
the hinted size or the default value of 8, the nTableMask
(which is usually nTableSize - 1
) is set to zero. This
means that hash & ht->nTableMask
will always result in the value zero as well.
So the arHash
array for this case only needs to have one element (with index zero) that contains an INVALID_IDX
value (this special array is called uninitialized_bucket
and is allocated statically). When a lookup is performed,
we always find the INVALID_IDX
value, which means that the key has not been found (which is exactly what you want for
an empty table).
Memory utilization
This should cover the most important aspects of the PHP 7 hashtable implementation. First lets summarize why the new
implementation uses less memory. I’ll only use the numbers for 64bit systems here and only look at the per-element size,
ignoring the main HashTable
structure (which is less significant asymptotically).
In PHP 5.x a whopping 144 bytes per element were required. In PHP 7 the value is down to 36 bytes, or 32 bytes for the packed case. Here’s where the difference comes from:
- Zvals are not individually allocated, so we save 16 bytes allocation overhead.
- Buckets are not individually allocated, so we save another 16 bytes of allocation overhead.
- Zvals are 16 bytes smaller for simple values.
- Keeping order no longer needs 16 bytes for a doubly linked list, instead the order is implicit.
- The collision list is now singly linked, which saves 8 bytes. Furthermore it’s now an index list and the index is embedded into the zval, so effectively we save another 8 bytes.
- As the zval is embedded into the bucket, we no longer need to store a pointer to it. Due to details of the previous implementation we actually save two pointers, so that’s another 16 bytes.
- The length of the key is no longer stored in the bucket, which is another 8 bytes. However, if the key is actually a
string and not an integer, the length still has to be stored in the
zend_string
structure. The exact memory impact in this case is hard to quantify, becausezend_string
structures are shared, whereas previously hashtables had to copy the string if it wasn’t interned. - The array containing the collision list heads is now index based, so saves 4 bytes per element. For packed arrays it is not necessary at all, in which case we save another 4 bytes.
However it should be clearly said that this summary is making things look better than they really are in several respects. First of all, the new hashtable implementation uses a lot more embedded (as opposed to separately allocated) structures. How can this negatively affect things?
If you look at the actually measured numbers at the start of this article, you’ll find that on 64bit PHP 7 an array with
100000 elements took 4.00 MiB of memory. In this case we’re dealing with a packed array, so we would actually expect
32 * 100000 = 3.05 MiB memory utilization. The reason behind this is that we allocate everything in powers of two. The
nTableSize
will be 2^17 = 131072 in this case, so we’ll allocate 32 * 131072 bytes of memory (which is 4.00 MiB).
Of course the previous hashtable implementation also used power of two allocations. However it only allocated an array with bucket pointers in this way (where each pointer is 8 bytes). Everything else was allocated on demand. So in PHP 7 we loose 32 * 31072 (0.95 MiB) in unused memory, while in PHP 5.x we only waste 8 * 31072 (0.24 MiB).
Another thing to consider is what happens if not all values stored in the array are distinct. For simplicity lets assume
that all values in the array are identical. So lets replace the range
in the starting example with an array_fill
:
$startMemory = memory_get_usage();
$array = array_fill(0, 100000, 42);
echo memory_get_usage() - $startMemory, " bytes\n";
This script results in the following numbers:
| 32 bit | 64 bit
------------------------------
PHP 5.6 | 4.70 MiB | 9.39 MiB
------------------------------
PHP 7.0 | 3.00 MiB | 4.00 MiB
As you can see the memory usage on PHP 7 stays the same as in the range
case. There is no reason why it would change,
as all zvals are separate. On PHP 5.x on the other hand the memory usage is now significantly lower, because only one
zval is used for all values. So while we’re still a good bit better off on PHP 7, the difference is smaller now.
Things become even more complicated once we consider string keys (which may or not be shared or interned) and complex values. The point being that arrays in PHP 7 will take significantly less memory than in PHP 5.x, but the numbers from the introduction are likely too optimistic in many cases.
Performance
I’ve already talked a lot about memory usage, so lets move to the next point, namely performance. In the end, the goal of the phpng project wasn’t to improve memory usage, but to improve performance. The memory utilization improvement is only a means to an end, in that less memory results in better CPU cache utilization, resulting in better performance.
However there are of course a number of other reasons why the new implementation is faster: First of all we need less allocations. Depending on whether or not values are shared we save two allocations per element. Allocations being rather expensive operations this is quite significant.
Array iteration in particular is now more cache-friendly, because it’s now a linear memory traversal, instead of a random-access linked list traversal.
There’s probably a lot more to be said on the topic of performance, but the main interest in this article was memory usage, so I won’t go into further detail here.
Closing thoughts
PHP 7 undoubtedly has made a big step forward as far as the hashtable implementation is concerned. A lot of useless overhead is gone now.
So the question is: where we can go from here? One idea I already mentioned is to use “fully packed” hashes for the case of increasing integer keys. This would mean using a plain zval array, which is the best we can do without starting to specialize uniformly typed arrays.
There’s probably some other directions one could go as well. For example switching from collision-chaining to open addressing (e.g. using Robin Hood probing), could be better both in terms of memory usage (no collision resolution list) and performance (better cache efficiency, depending on the details of the probing algorithm). However open-addressing is relatively hard to combine with the ordering requirement, so this may not be possible to do in a reasonable way.
Another idea is to combine the h
and key
fields in the bucket structure. Integer keys only use h
and string keys
already store the hash in key
as well. However this would likely have an adverse impact on performance, because
fetching the hash will require an additional memory indirection.
One last thing that I wish to mention is that PHP 7 improved not only the internal representation of hashtables, but
also the API used to work them.  In PHP 7 you just write
zend_hash_find(ht, key)
and get back a zval*
. Generally I find that writing extensions for PHP 7 has become quite a
bit more pleasant.
Hopefully I was able to provide you some insight into the internals of PHP 7 hashtables. Maybe I’ll write a followup article focusing on zvals. I’ve already touched on some of the difference in this post, but there’s a lot more to be said on the topic.


--- layout: post title: Game interfaces and anonymity date: 2004-12-21 00:00:00 categories: mobile play social ---
Speak Up Whilst I Kill You; voice in games seems, as Greg Costikyan noted, to be very natural. Look at Xbox live, Mario Party 5, even Donkey Konga uses sound input (err I think) to detect clapping...
Xbox live raises a whole set of issues on its own, because you end up playing with people you don't know (or sometimes, even speak the same language as!)... the others will usually be played in an established social setting. I've written about this before: IMHO the games industry will be the first guys to explore how you contact and interact with strangers whilst retaining privacy.


An item represents a Dungeon Souls item that is spawned in chests during runs. Items can have different classes, effects, prices and rarities, depending on what you desire. Keep in mind that an item will always have access to the current hero's data, such as health, damage, etc..
An item definition contains the following Game Variables:
| Name | Description | Required |
|---|---|---|
| NAME | The name of the item shown in-game. | True |
| MAX_STACKS | The maximum amount of stacks that the item can have. | True |
| DESCRIPTION | The description of the item shown in-game. | False |
| SPRITE | The sprite definition to assign to this item. | True |
| TYPE | The type of the item, which specifies the behaviour it will have. Can be one of the following:
| True |
| RARITY | The rarity of the item, which determines on which chests it is allowed to be spawned. Can be one of the following:
| True |
| PRICE | The base price of the item. | True |
| ON_PICKUP_FUNCTION | The function to call when the item is picked up. | False |
| ON_ACTIVE_FUNCTION | The function to call when the item is activated, when rarity is "item_active" or "item_consumable". | False |
| ON_STEP_FUNCTION | The function to call at each step of the game, when rarity is "item_passive". | False |
The item code is stored in the Dungeon Souls Item (.dsitem) file.
In Dungeon Souls, items can have their description change depending on the amount of stacks the hero currently has. As such, the description of the item definition has a special format to support this case.
Anytime you want to specify another description, depending on the stack count, you should use the following format:
{first description here|second description here|...}
Depending if your description has a linear dependency on the stack count of the item, you can also use the following format to account for modularity in a easier manner:
{<base_value>|<+|-><increment_value>}
Let's take a look at examples of these two formats. For the first format, let's say I have an item with the following description defined:
[DESCRIPTION]="{Increases your drop rate by a third|Increases your drop rate by a billion|You are the luckiest person ever.}";
With the previous description format, if its the first time the player is viewing the item description, then its description will be "Increases your drop rate by a third". However, if the player already had a stack count of two of this item, the description shown when picking the item the third time would be "You are the luckiest person ever.".
Similarly, the second format also completes the information, but this time around it is possible to define the description's behaviour, regardless of the max stacks defined. For example, let's consider the following description:
[DESCRIPTION]="Increases your max health by {2|+8} and reduces your defense by {2|+2}";
What this means is that, at first, the description will be completed to "Increases your max health by 2 and reduces your defense by 2". The second time the player picks the item, its description will be "Increases your max health by 10 and reduces your defense by 4". This happens because, for example, {2|+8} states to the engine that it should start with the value 2, then, for each stack count, add 8 to that value and complete the description.
Here follows an example of the definition of an item:
define item item_Red_Book
{
[NAME]="Red Book";
[MAX_STACKS]=3;
[DESCRIPTION]="+{4|+4} magical damage.";
[SPRITE]=spr_Red_Book;
[TYPE]="item_passive";
[PRICE]=50;
[RARITY]="item_common";
#[ON_PICKUP_FUNCTION];
#[ON_ACTIVE_FUNCTION];
[ON_PICKUP_FUNCTION]=redBookPickup();
#Place code here...
}


Test for the Combination of the "ba-if" Partial and the "ba-class" Partial
Test ba-if simple
Expected Behaviour (Class/Background seperate):
If:
{{=value}}
Hide Binding
Background:
{{=value}}
Hide Binding
Actual Behaviour
{{=value}}
Hide Binding
Show/Hide


Who are we?
The Roux Academy gets thousands of submissions every year for artists interesting in participating in the CAC exhibits, and selects approximately 200 distinct pieces of contemporary art for display in their collective exhibit. In addition, 12 individuals are honored as Featured Artists - each being granted his or her own exhibit hall to display entire collections or themed pieces.
Each Featured Artist has an opportunity to speak at one of our meetups and share his or her vision, perspective, and techniques with attendees on a more personal level than at our large conference. It is truly an honor to be a CAC Featured Artist and many past students artists who were featured at CAC have gone on to brilliant careers in art.


A State of Trance - YouTube Tracklist to Cue Sheet
Take tracklist from YouTube episode details:
Armin van Buuren YouTube channel
Episode number
Year
Tracklist
Transform
Cue sheet output


Some Non-traditional Marketing Tips
Marketing is generally unexciting to a ton of engineers, until it brings eyeballs which bring feedback and dollars. Marketing doesn’t have to always be cheesy campaigns or ads, it can often just be surfacing the things your customers actually do want to care about. My favorite type of marketing is when a service sells me on something at the exact time I want it. Here’s a few short tips on some non-traditional marketing that won’t seem sleezy but still can work quite well.
Email subscriptions to your blog
RSS is pretty dead, google went and killed it with google reader. Sure there’s some decent replacements if you’re really tied to it. In particular newsblur by @samuelclay is a great reader. But now days content emerges on twitter, fb, and ranking services, then later is discovered via search. Both of these work pretty well, but twitter is ephemeral for so many. Email still converts incredibly well, if people are abandoning rss but still care about your content give them the ability for it to be put right in front of their face via email.
Market in transactional emails
Have emails that include receipts? Account confirmations? General notices? No not a monthly newsletter! Transactional emails are obviously valuable to your users. Why not include a small call out to your latest announcement? Have a central hook that your emails can check from and simply include a small call to action within there.
Credit to @stevenbristol on strong business podcast for this one
Retarget to your existing users
In a similar vein of notifying your existing customers in transactional emails about news, you should be doing this all over the web. Retargeting is great to convert people once you’ve already got them on a landing page, but its also incredibly useful to get existing users to use a specific feature. If you track if they’ve never used a feature retargeting is a great way to make them aware of it, and once they’ve used it just count it as a conversion.
My favorite retargeting provider perfect audience makes this quite convenient as they allow a bit more control than most retargeting services
In conclusion
Marketing doesn’t have to be throwing your product and messaging in someones face, but you should make your users aware of it. The more engaged they are they more they’ll stick around and be happy about using you’re product, assuming you’ve built a good one. What are some of your favorite tips?


CHAR sets a fixed size for your data, whereas VARCHAR holds a variable amount, so if you use less characters than you expected it won't be wasting space; However, CHAR is must faster than VARCHAR
The limit can be modified to suit your needs, however CHAR can be 255 characters at its max
1970-01-01 00:00:00 UTC
1523629712 seconds
7.27 times faster


| |
|
| Import from {{settings.leagueRoot}} | |
| LOL launcher.exe{{leagueRootValid ? "" : " (invalid)"}} | (Revert or save changes before modifying.) |
| Show item names | |
| Version |
{{version.version}}
|
This doesn't look like a League of Legends folder to me. Please choose the correct location of lol.launcher.exe below.
| LOL launcher.exe: |


|
JTS Topology Suite version 1.13 | ||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object com.vividsolutions.jts.planargraph.GraphComponent
public abstract class GraphComponent
The base class for all graph component classes. Maintains flags of use in generic graph algorithms. Provides two flags:
Graph components support storing user context data. This will typically be used by client algorithms which use planar graphs.
| Field Summary | |
|---|---|
protected boolean |
isMarked
|
protected boolean |
isVisited
|
| Constructor Summary | |
|---|---|
GraphComponent()
|
| Method Summary | |
|---|---|
static GraphComponent |
getComponentWithVisitedState(java.util.Iterator i,
boolean visitedState)
Finds the first GraphComponent in a Iterator set
which has the specified visited state. |
java.lang.Object |
getContext()
Gets the user-defined data for this component. |
java.lang.Object |
getData()
Gets the user-defined data for this component. |
boolean |
isMarked()
Tests if a component has been marked at some point during the processing involving this graph. |
abstract boolean |
isRemoved()
Tests whether this component has been removed from its containing graph |
boolean |
isVisited()
Tests if a component has been visited during the course of a graph algorithm |
void |
setContext(java.lang.Object data)
Sets the user-defined data for this component. |
void |
setData(java.lang.Object data)
Sets the user-defined data for this component. |
void |
setMarked(boolean isMarked)
Sets the marked flag for this component. |
static void |
setMarked(java.util.Iterator i,
boolean marked)
Sets the Marked state for all GraphComponent s in an Iterator |
void |
setVisited(boolean isVisited)
Sets the visited flag for this component. |
static void |
setVisited(java.util.Iterator i,
boolean visited)
Sets the Visited state for all GraphComponent s in an Iterator |
| Methods inherited from class java.lang.Object |
|---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
| Field Detail |
|---|
protected boolean isMarked
protected boolean isVisited
| Constructor Detail |
|---|
public GraphComponent()
| Method Detail |
|---|
public static void setVisited(java.util.Iterator i, boolean visited)
GraphComponent
s in an Iterator
i
- the Iterator to scanvisited
- the state to set the visited flag topublic static void setMarked(java.util.Iterator i, boolean marked)
GraphComponent
s in an Iterator
i
- the Iterator to scanmarked
- the state to set the Marked flag topublic static GraphComponent getComponentWithVisitedState(java.util.Iterator i, boolean visitedState)
GraphComponent
in a Iterator
set
which has the specified visited state.
i
- an Iterator of GraphComponentsvisitedState
- the visited state to test
null
if none foundpublic boolean isVisited()
true
if the component has been visitedpublic void setVisited(boolean isVisited)
isVisited
- the desired value of the visited flagpublic boolean isMarked()
true
if the component has been markedpublic void setMarked(boolean isMarked)
isMarked
- the desired value of the marked flagpublic void setContext(java.lang.Object data)
data
- an Object containing user-defined datapublic java.lang.Object getContext()
public void setData(java.lang.Object data)
data
- an Object containing user-defined datapublic java.lang.Object getData()
public abstract boolean isRemoved()
true
if this component is removed
|
JTS Topology Suite version 1.13 | ||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |


I have learned a lot from programming. The funny thing is, a lot of what I learned has nothing to do with programming itself. Like a lot of people, I got by life just going through the motions. I took my AP classes, took my SAT, went to college, and prepared to get into grad school. Honestly, I was never excited about the whole process. I rarely had a class that I enjoyed fully, group projects were a pain, and talking to others about my major felt really tedious. I thought I was just weird or maybe everyone else was trying to pretend like they were having fun. Then I discovered programming.
Learning can be fun
It was a strange sensation. I found myself voluntarily googling for information. If I read something that I didn't understand, I would google that. If that led to something that I didn't understand, I would google again. As I became more engrossed with programming, I noticed that my leisure time slowly evolved into learning time. I spent less and less time doing "unproductive" things like scanning Flipboard or watching Netflix. I would instead keep trying to make time to go back and solve that coding challenge I had open. At some point, I came to realize that for the first time ever, I enjoyed learning.
Socializing can be fun
I've never been a social animal. I felt like I always had to constantly wear a mask and pretend like I was interested in whatever I was asking and talking about. I just chalked it up to my introversion. When I began meeting other programmers, this changed. I actually wanted to know about them. I wanted to know their story. I wanted to know what they were doing and how they were doing it. People suddenly became awesome.
Working with others can be fun
This is similar to socializing but my negative feelings for group projects are so strong that I had to give it it's own section. I hated group projects. I cannot emphasize that enough. For some reason, it always felt like the majority of the group didn't care about the project. This is not true with the people that I've met since I began programming, however. They love what they do and they want to be amazing at what they do. I cannot explain how much I love this mentality. I actually find myself excited to work with other people. There's just something about software development that makes people awesome human beings. It took me far longer than I expected but I've finally found what I want to do and it feels amazing.


jacobsHack! 2019, the 6th edition of jacobsHack!, is one of Germany's largest student-run hackathon where student hackers from all over the world come together to create and
collaborate on kick-ass projects over the course of 24 hours filled with programming, tech talks, games, and epic Nerf gun battles.
Applications for jacobsHack! 2019 are now closed.
jacobsHack! 2019 is made possible by:
jacobsHack! was previously sponsored by:
Our Location
Imprint
Terms & Conditions
Privacy Policy
Frequently Asked Questions
jacobsHack! is open to students (from high school students over 18 years of age to post-docs) and those that have graduated from university in the past twelve months.
In order to participate, you need to follow the MLH Code Of Conduct.
Yes, you can also participate even if you are not a coder.
Participation is not only about coding, e.g. graphic designers can be essential to teams by making the hack look more professional.
Providing ideas for projects also counts as participation.
In addition, there will also be mentors willing to help you to learn to code at the event if you are interested.
Admission is free!
We will provide food, beverages, and swag throughout the event.
Yes!
We are giving up to 25€ if you’re travelling from within Germany and
up to 100€ if you’re travelling from outside of Germany.
As a rule, we want to give all applicants the opportunity of joining jacobsHack!,
but please be aware that we may not be able to cover 100% of your costs.
Please also note that travel reimbursements can not be guaranteed for everyone.
We’ve got you covered.
We’ll take care of providing meals at the event from breakfast on Saturday to Brunch on Sunday.
If you have dietary restrictions, we’ll try our best to accommodate them.
Hacking all night can get tiring.
We’ll have a few bean bags and air mattresses in a quiet room for you to nap at the venue.
We can also connect you to students at Jacobs who generously offered their rooms for you to sleep and shower.
Bring your laptop along with you, and all tech you think you’ll need or use.
We’ll take care of the food, beverages, stickers, and much more.
Feel free to bring your pillows, toiletries, headphones, etc.
jacobsHack! takes place at an international university in Bremen, Germany.
You can find the directions from main public transit locations here.
If you’re coming from outside Bremen, we’ll try our best to provide travel reimbursements to subsidize your travel to jacobsHack!.
You can work in teams of up to 4 people.
If you don’t have a team now, don’t worry!
We’ll have team formation and ideation events geared towards helping you find people to work with throughout the event.
We are looking for a diverse group of hackers at our hackathon.
For this we will ask you a couple of questions in the application.
That said, we are looking for anyone who is creative or just simply passionate for technology.
Simply head to our registration portal.
Convince us why you are amazing and we will hopefully see you in Bremen in November!
We’ll accept applicants on a rolling basis.
jacobsHack! is an MLH hackathon.
Major League Hacking generously provides us with their hardware lab that includes a variety of hardware including and not limited to Arduino, Myo armband, Muse headband, Leap Motion, Spark Core, pebble, and Oculus.
Everything you create belongs to you.
We don’t claim any rights on your Intellectual property or the intellectual property generated by you during the hackathon or outside the hackathon.
However, we reserve the right to use your submissions for promotional purposes of jacobsHack!, see the Terms and Conditions for details.


Concurrency Control Strategies for Secret Agents
In the 1963 movie “Dr. No,” the first in the James Bond series, Bond travels to Jamaica for a case, and he knows that his enemies are watching his every move. He knows his enemies are smart, but he’s smarter. To keep them from prying into his plans, he can’t simply lock them out of his room, he needs to be a little more sly—as any reputable villain could surely pick a lock. So he places a hair on the door frame, knowing that in the sure event that his room is infiltrated while he’s out, he’ll see that the hair has moved and can abondon or change his plan if needed. It’s a brilliant tactic, and saves him time, effort, and constraints on his travel that he’d incur by trying to securely lock down his room as he moves from place to place.
How would this scenario look in code? Well, let’s introduce a secret mission, in Ruby:
class SecretMission
def initialize
@files = Array.new(5) { |i| "File #{i + 1}" }
end
def read(name)
while file = @files.shift
puts "#{name} is reading #{file}"
sleep(0.1)
end
end
def accept
puts "Mission Accepted"
end
end
The mission will contain some files that need to be read. Bond will accept the mission once he reads the files. But, there are also some villains out there trying to read the files.
mission = SecretMission.new
villains = ["Odd Job", "Jaws", "May Day"]
threads = []
threads << Thread.new do
mission.read("Bond")
mission.accept
end
villains.map do |spy|
threads << Thread.new do
mission.read(spy) if rand(0..3) == 0
end
end
threads.map(&:join)
With everything running in a separate thread, we get something like this output:
Bond is reading File 1
Odd Job is reading File 2
Jaws is reading File 3
Bond is reading File 4
Jaws is reading File 5
Mission Accepted
Since there’s no coordination of who is reading the files, a couple spies can sneak in. This is bad news. Bond just accepted a doomed mission because he didn’t realize that his plans were being read by the villains at the same time.
Maybe we can make him a little safer if we lock down the files when
they’re being read. We could add a mutex to the SecretMission
class
to use when reading the files:
class SecretMission
def initialize
@files = Array.new(5) { |i| "File #{i + 1}" }
@mutex = Mutex.new
end
def read(name)
until @mutex.try_lock
puts "#{name} is waiting"
sleep(0.3)
end
puts "The files are gone!" if @files.empty?
while file = @files.shift
puts "#{name} is reading #{file}"
sleep(0.1)
end
@mutex.unlock
end
def accept
puts "Mission Accepted"
end
end
Now when we run our spies in separate threads, we consistently see something like this (assuming Bond’s thread is the first to read):
Bond is reading File 1
May Day is waiting
Bond is reading File 2
Bond is reading File 3
May Day is waiting
Bond is reading File 4
Bond is reading File 5
Mission Accepted
The files are gone!
Bond gets to the files, acquires the lock, and the other threads are locked out for the duration of his reading. But, let’s assume that using this lock is time consuming and really draining the MI6 budget. Furthermore, once Bond has the lock, the other spies have to wait around for the lock to be available, and they just cause trouble.
So let’s try to emulate Bond’s hair on the door trick and allow us to check whether any villains have caught up to him so that we can then abort the mission and throw them off of his tracks.
First, let’s change our read
method to return how many files are read, and change
the accept
method to take a parameter for how many files a spy was able to read.
class SecretMission
def initialize
@files = Array.new(5) { |i| "File #{i + 1}" }
end
def read(name)
puts "The files are gone!" if @files.empty?
read = 0
while file = @files.shift
puts "#{name} is reading #{file}"
sleep(0.1)
read += 1
end
read
end
def accept(read)
if read == 5
puts "Mission Accepted"
else
puts "Abort Mission!"
end
end
end
Then, let’s change Bond’s behavior so that he can signal how many files he got to:
threads << Thread.new do
files_read = mission.read("Bond")
mission.accept(files_read)
end
Now, we could see Bond read all of the files successfully if none of the villains find them, or we could see something like this:
Bond is reading File 1
Odd Job is reading File 2
Odd Job is reading File 4
Bond is reading File 3
Odd Job is reading File 5
Abort Mission!
This is a nice, lightweight option that allows us to always know whether the mission is compromised, without any waiting by any of the spies.
From Pessimistic to Optimistic Locking
What we’ve done here is moved the concurrency control mechanism from a pessimistic lock using a mutex, to optimistic concurrency control, which assumes that nobody else is reading our files—until we verify that assumption at the end of our transaction. If we were using a database to read and write our data, we could use a pessimistic lock by obtaining a lock for a specific row in the database.
Let’s use another example, in which we have orders that we want to cancel. We can only cancel orders if they are currently in a “pending” state. It also causes a lot of problems to cancel an order twice, or an order that is not pending. But we have lots of updates happening concurrently, so we need some way to maintain the integrity of our concurrent state transitions. We could start with a pessimistic lock. We’ll assume we’re using ActiveRecord for this example.
order = Order.find(order_id)
order.with_lock do
if order.status == 'pending'
order.update({ status: 'cancelled' })
end
end
If we’re using PostgreSQL as our database, this will perform a SELECT FOR UPDATE
on the record prior to yielding to the block to perform. Once this transaction gains
the lock through the SELECT FOR UPDATE
, the database will not allow other
transactions to modify the row until our transaction is committed, after the block
finishes. This gives us assurance that nothing else will change the order while the current
thread is using it. But sometimes this is a heavy tool for the job. For one,
any other threads trying to use the row will block, which could degrade our
performance.
We could avoid the need to acquire a lock, and wait for the lock, by changing
this procedure to an optimistic lock. All we need to do is tell the database
the state of the object that we have, and let it confirm that that
is indeed the current state. If it is not the current state, we know that
another transaction was working at the same time. We can do this by using an
UPDATE WHERE
. In ActiveRecord that would look like this:
order = Order.find(25)
if order.status == 'pending'
rows_affected = Order.where({
id: order_id,
status: 'pending'
}).update_all({ status: 'cancelled' })
raise StaleDataError if rows_affected == 0
end
The above query should generate the SQL:
UPDATE orders SET orders.status='cancelled' WHERE orders.id=25 AND orders.status='pending';
A SQL update returns the number of rows that were updated, so we can check the return
value from our update and know that we’ve run into concurrent updates if our update
returns 0
.
Note: If you’re using ActiveRecord, or another ORM to do a similar optimistic lock, you should confirm that this is actually the SQL that gets generated. I’ve seen ActiveRecord convert queries like this to a sub-select, which negates the benefit of our lock because we’re left with a race condition between when the sub-select executes and when other concurrent updates commit.
Multi-Version Concurrency Control
PostgreSQL
Although our optimistic locking strategy isn’t explicity acquiring a lock, we could
still block other transactions. Certain databases might block both reads and writes
while we are performing the update. PostgreSQL will only block other writes.
When using an optimistic locking strategy in PostgreSQL, it’s important to
know why this works, and how it affects other transactions. In order to perform
our UPDATE WHERE
while maintaining our data consistency and also not blocking
other threads from reading data, PostgreSQL uses a technique called Multi-Version
Concurrency Control (MVCC). Other databases also use this pattern, but I’ll
focus on PostgreSQL here.
PostgreSQL executes each statement inside of a transaction with the Read Committed isolation level. An isolation level determines what kinds of changes to data are shared between transactions. There are other isolation levels available, but Read Committed is the default. In Read Committed isolation, PostgreSQL allows other threads to read the row without blocking, though other updates will need to wait for other concurrent updates to complete. How does this work? Well, the key here is that each record in the database isn’t just one row. It’s actually many rows that PostgreSQL is constantly marking as unavailable after updates or deletes, and available as they become the most recent version (it’s actually a slightly more complicated process of comparing transaction IDs stored in system columns, but let’s use this simplification). PostgreSQL eventually goes back and cleans up the unavailable rows through the autovacuum process.
So, back to our example, say we execute our query at time T1
:
BEGIN; UPDATE orders SET orders.status='cancelled' WHERE orders.id=25 AND orders.status='pending'; COMMIT;
PostgreSQL begins a transaction in Read Committed isolation, and for the
duration of this transaction it will only see data committed and marked as
available prior to T1
. Then, say we execute a concurrent query at time T2
to:
BEGIN; SELECT status FROM orders WHERE orders.id=25; COMMIT;
This SELECT
will only see row versions that were committed and available
prior to T2
. Assuming we only have these two queries running, the SELECT
will see the same version of the row that our first UPDATE
is
seeing—that which was committed prior to T1
, with the status as
“pending”. So this query will return “pending”. (Side note: a SELECT
will
also see data changed by an UPDATE
within its own transaction).
Let’s throw in another update and see what happens. Assume our SELECT
completed
at time T3
and returned “pending”, but our UPDATE
is still running. Another
transaction might start at time T4
to actually start the order:
BEGIN; UPDATE orders SET orders.status='started' WHERE orders.id=25 AND orders.status='pending'; COMMIT;
This transaction will see the version of the data committed prior to T1
and our first
update, so it will find a row with ID 25 and status “pending”. But it will see that the
row is currently held by a ROW EXCLUSIVE lock in our first transaction, so it will
need to wait. Let’s assume the first update commits at T5
. Our second update now
gets to re-apply its query to the row version as of T5
, so it will see that the status
is now not equal to “pending”, and it will not update the status to “started”.
So, we’re still eventually locking a row in our database, but the benefit of doing this through PostgreSQL’s MVCC implementation is that we minimize the amount of time that a lock is held, and the amount of time that our threads spend waiting to proceed with our business logic. This could be good or bad depending on how our program is structured.
If we perform some side effect-y things prior to updating the order, such as
sending a notification that the order is started, then we’ve actually been
notified about the concurrent update too late. On the other hand, if we do the
update before the business logic, then we know right away whether we can
proceed and avoid blocking while another thread performs its business logic.
When we use SELECT FOR UPDATE
by using order.with_lock
in ActiveRecord,
other threads will halt on trying to acquire the lock while the first executes
the in-memory logic and the database update. In many situations, but not all,
it’s more effecient to be optimistic and let things proceed until we know that
we’ve actually encountered a concurrency issue.
Clojure STM
Let’s take this full circle and see what a MVCC implementation of our secret file example would look like. For an in-memory implementation, we can use Clojure, as Clojure’s refs are implemented using Software Transactional Memory (STM) with MVCC.
(ns spies.core)
(def files
(->> (range 5)
(mapv #(format "File %s" (inc %)))
ref))
(defn read-file [spy files file]
(println (format "\n%s is attempting to read %s" spy file))
(alter files rest)
(println (format "\n%s is reading %s" spy file))
(Thread/sleep 300)
file)
(defn accept-mission [files]
(alter files (constantly ["A bad pun from Bond"]))
(println "\nMission Accepted"))
(def bond
(future
(dosync
(let [file-read (map #(read-file "Bond" files %) @files)]
(if (= 5 (count files-read))
(accept-mission files)
(println "\nAbort Mission"))))))
(defn villainize [villain]
(future
(when (zero? (rand-int 3))
(dosync
(if-let [file (first @files)]
(read-file villain files file)
(println (format "%s, the files are gone" villain)))))))
(def villains
(map villainize ["Odd Job" "Jaws" "May Day"]))
(defn -main [& args]
(let [futures (conj villains bond)]
(doall (map deref futures)))
(shutdown-agents))
In this code, we create a group of threads to read the files using future
.
Bond’s thread will try to read all the files and then leave a note for
the villains, whereas the villains will only try to read one file. The files
are kept in a ref
, which will only allow mutation while inside a transaction
using dosync
. While in the transaction, we can change the ref by using
alter
, which takes as arguments a ref and a function to call to alter the
ref. When we run this, we see something like this:
Bond is attempting to read File 1
Bond is reading File 1
Jaws is attempting to read File 1
Odd Job is attempting to read File 1
Bond is attempting to read File 2
Bond is reading File 2
Odd Job is attempting to read File 1
Bond is attempting to read File 3
Jaws is attempting to read File 1
Bond is reading File 3
Bond is attempting to read File 4
Bond is reading File 4
Bond is attempting to read File 5
Bond is reading File 5
Odd Job is attempting to read File 1
Jaws is attempting to read File 1
Mission Accepted
Jaws is attempting to read A bad pun from Bond
Odd Job is attempting to read A bad pun from Bond
Jaws is reading A bad pun from Bond
Odd Job, the files are gone
Jaws, the files are gone
You’ll notice that the threads trying to read for Jaws and Odd Job retried a
number of times while Bond’s thread was reading the files. This is caused by
Clojure’s LockingTransaction implementation retrying the call to alter
if the
transaction can’t obtain a write lock or if it finds that the ref has been
altered since its read point. No threads are blocked from reading the files, but
once a thread makes a call to alter
, it tries to acquire a write lock, and if
it can’t, it will retry from the beginning of the transaction starting from
dosync
.
Each thread sees the last committed version of the files when the transaction started.
So to start, each villain thread will see that there are five files in the ref,
and will try to remove one to be read by the spy by calling alter
. However,
Bond’s transaction has the write lock, so the other transactions will retry the
alter
of the first file a number of times, until Bond’s transaction commits and
releases the write lock. Then the villain threads will retry again because
Clojure’s STM detects that the ref has changed. This time they see the version
of the ref that Bond committed, with only his note left.
Tradeoffs
Given your options for concurrency control strategies—pessimistic/locking, optimistic/lock-free, or MVCC/hybrid—which one should you use? Well, like most decisions when writing software, it comes down to your needs for the specific problem you’re trying to solve. Each of these strategies present different tradeoffs that should be taken into account. To sum up, here’s what you get with each:
Pessimistic/Locking
Benefits:
- Exclusive access
- Possible stronger guarantee of integrity
Drawbacks:
- Lock contention
- Records are possibly completely inaccesible by other processes depending on implementation
Optimistic/Lock-Free
Benefits:
- Lower overhead
- No waiting or lock contention
Drawbacks:
- Deciding how to handle collisions or stale data
- Possibility of retrying operations with side-effects
MVCC/Hybrid
Benefits:
- Reads are never blocked
- Reads never block writes
Drawbacks:
- Cost of maintaining multiple versions of records (e.g. autovacuum)
- Handling retried transactions or stale data
- Isolation levels vary between implementations
When trying to solve a concurrency problem, keep in mind that there are many strategies available to you, and pick the one that best suits your specific needs. You don’t always need the brute force of a pessimistic lock. Bond knew the villians would break in, he just wouldn’t know when or what they had access to without the hair. You too can embrace the challenges of concurrency through different concurrency control strategies. With the right choice, you can thwart would-be concurrent invasions into your process just like a secret agent.


Home
HELLO
i'm here to assist you :)
{% csrf_token %} Question
answer
{% for answers in list%}
{{ answers.answer}}
{% endfor %}


Castle Douglas butcher celebrates having some of the best sausages in the UK
The pork sausages from Ballards made it to the final five of the champion of champions competition at the Butchers Shop of the Year Awards
by Stuart Gillespie, https://www.dailyrecord.co.uk/authors/stuart-gillespie/A Castle Douglas butcher’s sausages are among the best in Britain.
Jimmy Craig of Ballards on King Street recently returned home from the Butchers Shop of the Year Awards in London.
And while the shop’s pork sausages didn’t win the overall champion of champions sausage title, they did make it to the final five.
Jimmy said: “I didn’t know whether or not to go but I decided I would as I might never get the chance again. I’m glad I did.”
The competition, held at the Hilton London Bankside, pitted award-winning sausages from across the UK and Ireland against each other.


Home
Libraries
>
library:html
>
INTRO library:html
prev
next
This library provides support for generating
HTML
.


--- layout: archive title: Zulip Chat Archive permalink: /stream/113489-new-members/topic/Beginner.20question.3A.20inequality.html ---
Hi. What is the preferred way to prove something like: 0 ≠ 1? Right now I'm using:
example : 0 ≠ 1 :=
begin
intro h, injection h
end
I'm asking because there seems to be multiple ways of doing the same thing in Lean. Some may introduce me to some new tactics.
@Chu-Wee Lim This very much depends on what 0
and 1
are. Are the natural numbers or integers or real numbers?
There are many ways, if I saw this or something similar I'd write example : 0 \ne 1 := dec_trivial
to use the fact naturals are decidable, however this lemma is in core (so you can apply it...) but the core proof is here https://github.com/leanprover/lean/blob/ceacfa7445953cbc8860ddabc55407430a9ca5c3/library/init/data/nat/lemmas.lean#L47
In my code above, natural numbers.
The proof of this fact is usually called zero_ne_one
. Here is mathlibs proof for real numbers: https://github.com/leanprover-community/mathlib/blob/b5b40c749f2f581778e5d72907eca1aa663962b1/src/data/real/cau_seq_completion.lean#L120
The generic way to do it is the norm_num
tactic.
i can never remember the name of lemmas unless i look it up. for stuff like this that is straightforward, you can use example : 0 ≠ 1 := λ h, nat.no_confusion h
Aha, this lets me use my trick for the shortest proof ever:
example : 0 ≠ 1.
That's the way Kevin would have wanted to prove 1 ≠ 2
on his example sheets on quadratic equations...
that makes my lean server crash when I apply it to arbitrary lemmas
Can you give a MWE of the crash? It might be something fixable in 3.5.0c.
Aha, this lets me use my trick for the shortest proof ever:
example : 0 ≠ 1.
How does this work? I've never seen the period in Lean before.
The period is sometimes required to terminate a statement if it is ambiguous whether the statement ends there or not (lean will otherwise proceed parsing, probably encounter the lemma
beginning the next statement, interpret the result as a function application and throw an error)
As for why it works... :shrug: Maybe lean tries dec_trivial
if you omit the definition of an example
?
Ah, got it
Not is just shorthand for a map to false, so we are just defining a function to false using an empty inductive definition (the match
-like syntax)
0 ≠ 1
expands to 0 = 1 → false
. In general, you can define functions (or prove implications) using the equation compiler, e.g.
example (A B : Prop) : A → B | ha := _
The equation compiler is more powerful than this example. If the variables are coming from an inductive type (A
), you can destruct them using this syntax.
example (A B : Prop) : (A ∨ B) → false | (or.inl ha) := _ | (or.inr hb) := _
0 = 1
is an inductive proposition. There's only one way to prove an equality, refl a : a = a
. But this can never be applied to prove 0 = 1
, since they're built with different constructors for nat
. The equation compiler figures out that this case is impossible, so you're left with zero applicable cases for the pattern match.
Adding a newline after example : 0 ≠ 1.
seems to crash the Lean 3.5.0 (nightly-2019-10-01) server. I'll try to MWE later.
Happens to me in 3.4.2 as well, but I can't get it to trigger from the command-line.
{% endraw %}Last updated: Apr 24 2020 at 19:02 UTC


Analysis
Your browser does not support HTML5 video.
Open Webcam
Upload Video
Easy to Use
Ready to use with your own content, or customize the source files!
The Team...
Subhankar Shah
Suvrata G
Swapnil Shobhit


Please Click on a Project Name to See More Information
Current Projects
Mini Sumo Robot
Autonomous Rover
MicroMouse
ArtBot - Kinetic
Intel-Cornell Cup
Line Follower
Past Projects
Mini Sumo Robot
Web Controlled Tankbot
RC Quadcopter


This webpage contains a form and an Ajax script that will receive data sent from the server. The form contains four input text boxes, for Name, Time, Date(day, date format), and Date(mm/dd/yy format). After the user enters their name in the Name text box and then clicks outside this text box, the Ajax script should access three php scripts on the server which will contain the Time, Date(day, date format), and Date(mm/dd/yy format) and return the Time and Date formats into their respective text boxes.
Time:


TkdApplication module.
MIT. See LICENSE for full details.
Standard themes.
The alternate theme.
The classic theme.
The default theme.
The Clam theme.


/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/ /*...*/ |
||
| 27 | package org.apache.http.impl.client.cache.memcached; |
|
|
||
/**
* This is a {@link KeyHashingScheme} based on the
* SHA-256
* algorithm. The hashes produced are hex-encoded SHA-256
* digests and hence are always 64-character hexadecimal
* strings.
*/ /*...*/ |
||
| 43 | 1 | public class SHA256KeyHashingScheme implements KeyHashingScheme { |
| 45 | 1 | private static final Log log = LogFactory.getLog(SHA256KeyHashingScheme.class); |
| 47 | @Override |
|
| 48 | public String hash(final String key) { |
|
| 49 | 1 | final MessageDigest md = getDigest(); |
| 50 | 1 | md.update(key.getBytes()); |
| 51 | 1 | return Hex.encodeHexString(md.digest()); |
| 52 | } |
|
| 54 | private MessageDigest getDigest() { |
|
| 55 | try { |
|
| 56 | 1 | return MessageDigest.getInstance("SHA-256"); |
| 57 | 0 | } catch (final NoSuchAlgorithmException nsae) { |
| 58 | 0 | log.error("can't find SHA-256 implementation for cache key hashing"); |
| 59 | 0 | throw new MemcachedKeyHashingException(nsae); |
| 60 | } |
|
| 61 | } |
|
| 62 | } |


Introduction to Kubernetes cluster
Kubernetes is designed as a highly available cluster of computers that are connected to work as a single unit. This abstraction allows us to deploy applications without thinking about which specific machines they need to run on. To make use of this new model of deployment, applications need to be packaged in a way that decouples them from individual hosts: they need to be containerized. This is different compared to how applications were deployed in the past, when they were directly installed on specific machines as packages deeply integrated into the host. Kubernetes role is to automate the distribution (scheduling) of application containers across a cluster in an efficient way. Kubernetes is an open-source platform and is production-ready.
A Kubernetes cluster is formed out of 2 types of resources:
- Master is coordinating the cluster
- Nodes are where we run applications
Summary:
- Kubernetes cluster
- Minikube
Kubernetes is a production-grade, open-source platform that orchestrates the placement (scheduling) and execution of application containers within and across computer clusters.
Cluster Diagram
The Master is responsible for managing the cluster. The master nodes will coordinate all the activity happening in your cluster like scheduling applications, maintaining their desired state, scaling applications and rolling new updates.
A node is a VM or a physical computer that is used as a worker machine in a Kubernetes cluster. Every node from the cluster is managed by the master. On a typical node you will have tools for handling container operations (like Docker, rkt) and Kubelet, an agent for managing the node. A Kubernetes cluster that handles production traffic should have a minimum of three nodes.
Masters manage the cluster and the nodes are used to host the running applications.
When we deploy applications on Kubernetes we tell the master to start our containers and it will schedule them to run on some node agents. Communications between the master and the nodes is done via an API exposed by the master. The same API is exposed towards the users in order to facilitate interaction with the cluster.
A Kubernetes cluster can be deployed on either physical or virtual machines. The recommended way to start a Kubernetes cluster for development purposes is by using minikube. Minikube creates a VM on your local machine and deploys a simple cluster containing only one node. Minikube is available for Linux, Mac OS and Windows systems. The minikube CLI provides basic bootstrapping operations such as: start, stop, status and delete. During this bootcamp we’ll use an online terminal with minikube pre-installed.
The name Kubernetes originates from Greek, meaning “helmsman” or “pilot”, and is the root of the words “governor” and “cybernetic”. K8s is an abbreviation obtained by replacing the 8 letters “ubernete” with 8.
Now that you know what Kubernetes is, let’s go to the online tutorial and start our first cluster!


I'm afraid these aren't annotated.


Nicki Chapman says her brain tumour hasn't grown six months after surgery
The TV favourite has revealed all about her recovery after going under the knife to remove part of the 'golf ball-sized' growth - and thanked the NHS and her 'hero' consultant
by Sam Elliott, https://www.mirror.co.uk/authors/sam-elliott/Nicki Chapman says her brain tumour hasn't grown at all six months after lifesaving surgery.
The brave 52-year-old told her fans the great news as she continues her incredible recovery.
Earlier this year, the Escape To The Country presenter shocked everyone after announcing she had been diagnosed with the aggressive cancer.
Nicki said her tumour was 'the size of a golf ball' in a worrying statement but since going under the knife things have taken a turn for the better.
The former Pop Idol judge took to Instagram to provide a very welcome update.
Nicki shared her progress and gave a big thumbs up at Charing Cross Hospital in a brilliant snap on the social media site.
She caption her photo: "I got the best news this week: Six months after my surgery, my consultant (also my hero) has said the remaining tumour hasn't grown.
"Small steps but a huge relief. My grateful thanks to the wonderful team #CharingCrossHospital #Neurosurgery & @ImperialNHS @NHSEnglandLDN @TheBrainTumourCharity."
She spoke in the summer on ITV’s This Morning - and praised the NHS.
“Someone told me it’s a dark gift when you get diagnosed with something like this," she said.
“I know what they mean. It absolutely changes your perspective.
“It was so scary. I was petrified and I remained as positive as I could.
“And now I look at people in a slightly different way. I don’t judge them so quickly. I hope now I am more patient, more kind, more forgiving.
"Before, I was quite judgmental. I hope all of life experiences change you and make you a better and stronger person.”
She added: “I knew the NHS were brilliant – I now literally worship their feet.
"They make you feel so special and as if you are the first person to have this. You are not.
“I have been fortunate. When you hear other people’s stories and you realise the outcome hasn’t been as good as mine, it makes you feel very grateful."


Nicolette Chambers
About
This is my first blog post
Read all about me coding adventures
This is my second blog post
Read all about me coding adventures
Web Wireframe Mockup
Mobile Wireframe Mockup


Economic capital is not only used for relative risk measurement and performance but also to determine the adequancy of an institution's absolute level of capital
Senior management "buy-in" is key
Models should be transparent and fully understood
Economic capital measures should capture all implicit and explicit risks
Uses
Business-level use
Credit portfolio management
Risk-based pricing
Customer and product profitability analysis
Customer segmentation and portfolio optimization
Management incentives
Enterprise-wide or group-level use
Relative performance measurement
Capital budgeting, strategic planning, target setting, and internal reporting
Acquisition/divestiture analysis
External communication
Capital adequacy assessment
Risk Measures
Choice of risk measure depends on:
Properties of the measure
The risk- or product-type being measured
Data availability
Complexity and usability trade-offs
Intended use of the measure
Important to fully understand advantages and limitations of a chosen measure
Desirable Characteristics of a Measure
Intuitive
Stable
Easy to compute
Easy to understand
Coherent
Simple and meaningful risk decompositions
Risk Aggregation Methodologies
Simple summation
Constant diversification
Variance-covariance matrix
Copulas
Full modelling/simulation
Validation
Provides a degree of confidence that assumptions are appropriate and is useful in identifying limitations of models
Recommendations for Supervisors
Use economic capital models in assessing capital adequacy
Ensure committment of senior management
Transparency and integration into decision making
Robust risk identification process
Understand implications of selected risk measures
Ensure risk aggregation is representative of risk profile


Your encryption key is connected to your password. You have the option to either keep all the data and encryption keys and just change the password or you can delete all the data and generate new encryption keys. Choose your option carefully.


90 Every object is created with predeﬁned methods for set, method, delete-var, delete-method, and clone. It has one predeﬁned variable, parent. Objects without a parent are created by calling new object: As before, we provide procedures to call an object’s dispatch procedure and then call the method. But in this version, we provide the desired object as the ﬁrst method input. We provide one procedure for Command methods and one for Reporter methods: (Remember that the “Input list:” variant of the run and call blocks is made by dragging the input expression over the arrowheads rather than over the input slot.) The script below demonstrates how this prototyping system can be used to make counters. We start with one prototype counter, called counter1. We count this counter up a few times, then create a child counter2 and give it its own count variable, but not its own total variable. The next method always sets counter1’s total variable, which therefore keeps count of the total number of times that any counter is incremented. Running this script should [say] and (think) the following lists: [1 1] [2 2] [3 3] [4 4] (1 5) (2 6) (3 7) [5 8] [6 9] [7 10] [8 11]


Extensions
Extension 1: Image Processor With Iteration (6 points):
- Authors
Manipulating an Image Raster
Directions: In the imagetransforms package, modify the provided Transforms Java program
to implement the methods as described below.
Your methods will use iteration (either while loops or for loops) to operate on the pixels of a picture.
Notes
- To run this extension, right (control) click on Main and choose Run as... then Java Application.
This extension uses
the same base code as the filter extension.
-
The Picture class is a Sedgewick class whose API is documented on page 720 of our text.
The coordinates are expressed using the standard in computer science graphics:
the coordinate (x,y) denotes
the pixel that is
- x pixels to the right of the leftmost edge of the picture
- y pixels down from the top edge of the picture
Thus, (0,0) is the top left corner of the picture.
-
Pixel addressing follows the common Java convention: if there are w horizontal pixels, then 0 is
the first (leftmost) and w-1 is the last (rightmost).
-
Almost all of the methods are written in terms of two Picture parameters:
- source: the picture to be used as input to your transformation
- target: the picture area to be used as output from your transformation
There is just one exception: the gradient method produces its output
without needing a source. Its only parameter is
target.
- Each Picture has a width and a height, and these can be obtained
for a Picture p as follows:
int width = p.width();
int height = p.height();
-
To find the Color of a pixel at location x,y, you use
Color c = source.get(x,y);
-
To set the Color of a pixel at location x,y to the color c, you use
target.set(x,y,c);
Instructions
Each of the methods described below is found in the Transforms class.
- The provided method flipHoriz(Picture source, Picture target) flips the image horizontally.
Look at the code given to you for this example
carefully. It is broken into simple steps and the comments help explain why the pixel indexing works.
- Complete the method flipVert(Picture source, Picture target) that flips the image vertically.
- Complete the method
flipHorizLeftHalf(Picture source, Picture target)
that flips the left half of the image horizontally.
The left half of the target image should be same as the source, but the right half of the target image should
be the mirror of the left half of the source.
- Complete the method
flipVertBotHalf(Picture source, Picture target)
that flips the bottom half of the image vertically.
- Complete the method gradient(Picture target) that takes a single Picture
as a parameter.
Your code
should create a color gradient by computing the following for each pixel:
- The amount of red in each pixel increases gradually from 0 at the left edge of the image, to 255 at the right edge of the image.
- The amount of green in each pixel increases gradually from 0 at the top edge of the image, to 255 at the bottom edge of the image.
- The amount of blue in every pixel should be 128.
Thus, each pixel will have a different color depending on its position. For example, the pixel at the top left will have red=0, green=0, and blue=128. The pixel about 1/4 of the way down on the right edge will have red=255, green=64, and blue=128.
Develop an expression
for the amount of red and green in each pixel, given the x and y position of that pixel and the width and height of the image:
int amountRed = .....
int amountGreen = ....
Then set the pixel at (x,y) to a color based on those computations:
target.set(x, y, new Color(amountRed, amountGreen, 128));
Note There are other methods in the Transform class, but they
are the subject of other extensions. Once you have completed the above work,
demo and you are done with this extension.
End of extension 1
Extension 2: Loop Invariants (7 points):
- Authors
Loop invariants are a tool for proving that a loop computes some useful
result. This topic is covered in a discrete math course, but you can try
your hand at some loop invariant proofs in this extension.
However, you must agree to the following:
- You will watch this video before you ask any questions.
- You will meet with the instructor as indicated in the steps below.
- Those meetings will take place in office hours during the semester,
or during times otherwise arranged with the instructor.
- Like all extensions, you get to choose whether you want to do
this extension. However,
if you want to do it, then your work on this extension must be complete before the first extension deadline.
Warm Up
Loops can be used to execute many simple operations. For instance:
For some a and b:
int ans = 0;
int i = 0;
while(i != b){
i = i + 1;
ans = ans + a;
}
This code computes the product of a and b.
We have discussed this in this video,
and you can find the code in the loopinvariants package of the
extensions folder. You are encouraged but not
required to create other classes in
that package to help you with your work below.
Part 1
Consider the following examples:
int ans = a;
int i = 0;
while(i != b){
i = i + 1;
ans = ans + 1;
}
The above code computes the sum of a and b.
int ans = 1;
int i = b;
while (i != 0){
i = i-1;
ans = ans * a;
}
The above code computes a to the power of b
-
int ans = 0;
int i = a;
while (i >= b) {
i = i - b;
ans = ans + 1;
}
The above code computes a divided by b using integer arithmetic.
- Find the Loop Invariants of these three loops. Once you have found them, talk to the professor
to make sure that they are correct.
- Sketch a mathematical proof to show that these loops actually return what we say that they return. You will not need to turn this in to the professor,
but it will be good practice for Part 2.
Part 2
Consider the following code:
int power = 0;
int i = a;
while (i%2 == 0) {
i = i/2;
power = power + 1;
}
- Create a table of values for a, i, and p for a couple of initial values of a. Use this table to find the relationship between a, i and p.
Hint: a is a function of i and p.
- This relationship is the Loop Invariant of this code. Write a mathematical proof that the loop invariant stays constant throughout the iterations.
Every step must proceed from what came before it, with no gaps in logic. Any flaw will cause your submission to be rejected, but you can continue revising
your proof until the end of the semester when extensions are finally due.
- What does this relationship say about the natural numbers (your values of a)? The fact that this relationship is true for all numbers is
actually a mathematical theorem.
That theorem is used in the Miller–Rabin primality test, which is a fast
probabilistic algorithm for testing the primality of an integer:
- If that test says no, then the
integer in question is definitely not prime.
- If that test says yes,
the the integer in question might be prime.
The uncertainty can be reduced
arbitrarily by more testing.
To Demo
You must
- Show the loop invariants of all of the above loops
- Have a mathematical proof for the correctness of the outcome of the final loop
- Show your final work to the instructor with your name, your WUSTL key, and your student ID
- Understand your own proof. You will be asked questions about it when you turn it in
End of extension 2
Extension 3: One-Rep Max Weight Calculator (3 points):
- Authors
Disclaimer:
- The values computed in this assignment are based on
published formulas, but you are advised to undertake this and all forms of
exercise with the advice and consent of a physician.
-
In particular, performing
a one-rep max movement unprepared or unsupervised can result in injury.
-
You are therefore especially cautioned against that form of training without
adequate supervision and coaching.
The authors of this extension and all personnel involved
with this course are not licensed medical
care providers; they represent that they have no exepertise in
diagnosing, examining, or treating medical conditions of any kind,
nor in determining the effects of any specific exericse.
The data computed by this exercise are for informational and instructional
purposes only.
Overview
In weight training, the volume of work completed in
one exercise (often called a set) is typically specified as a given weight that
is moved a specified number of times. These are respectivelly
called the weight and reps (abbreviates repetitions)
of that set.
In this extension, you will create a one-rep max calculator.
This calculator hypothetically calculates a weight that a subject
could move for one repetition, given that the same subject can successfully
complete r reps (in the range of
2…12) at a lighter weight.
-
Beyond 12 reps,
the formula we use is not considered accurate.
- The stated value for r is generally considered to be
the number of times the weight
can be moved before failure: the subject can complete r reps
at the stated weight, but no more.
While a person may never attempt that one-rep max movement, the one-rep
max weight is canonical, in that it can then be used to compute
lighter weights that should be feasible for the subject at a desired number
of reps.
Your solution will compute and print:
- The one-rep max weight based on a formula described below.
- The weight that should be feasible for a stated number of reps.
- Percentages of the one-rep max weight from 95% to 50% in decrements
of 5%.
Example
Consider a subject who can successfully
bench
225 pounds 10 times before failure.
- What is this subjects current one-rep max bench weight?
- How much weight should that subject be able to bench to get 5 reps before failure?
- What percentage of this subject's max bench is the weight that can
be benched 5 times?
- Input
-
- Successful weight: 225 pounds
- Successful reps: 10
- Desired reps: 5
- Output
-
One-rep max: 300
Weight for 5 reps: 255
95% 1 RM: 285
90% 1 RM: 270
85% 1 RM: 255
80% 1 RM: 240
75% 1 RM: 225
70% 1 RM: 210
65% 1 RM: 195
60% 1 RM: 180
55% 1 RM: 165
50% 1 RM: 150
Procedure
- First take a look at
this one-rep max
caculator.
- If you try it for some sample values, you will see that it
produces results that may not work in an actual gym, because the smallest plate
one can find in most gyms is 2.5 pounds.
-
Our calculator takes in a third input, which is how many reps the person
wants to perform,
and calculates a weight to be performed at that number of reps.
-
Our
one-rep max
calculations will be based on the
Epley Formula,
so study that material sufficiently well to complete this extension.
- Create a OneRepMax class in the onerepmax package
of the extensions folder.
- Arrange for that program to prompt the user for the inputs needed for
this computation.
- Compute and print the results as shown in the sample ouptut above for
the inputs provided in the run of your code.
- You must:
- Check that the inputs provided are reasonable. Print a suitable message and
exit if any inputs are unreasonable.
- Use iteration to produce the table of percentages of the one-rep max
weight.
- Produce weight values that are rounded to the nearest 5 pounds,
so that the least weight needed on a bar is 2.5 pounds on each side.
End of extension 3
Extension 100: Rock-Paper-Scissors (C++) (6 points):
- Authors
Issues:
Under development. Do not do this yet!
Rock-paper-scissors
The game of
Rock-Paper-Scissors (hereafter, RPS) is a two-player game that can be used to avoid boredom and to settle
disputes.
In this extension you will rewrite the lab from Module 2 in C++.
Procedure
Update your workspace as usual, and find the Module 2 package
in the extensions source folder. Create a new source file rps there,
and you are ready to begin your development.
It is suggested that you develop code
in small steps, so that you can proceed from confidence to confidence, and
not have a big pile of untested code to debug at the end.
To help motivate this approach, the TAs will not help you unless you have
shown progress based on these steps. Ask for help as soon as you need it,
but please follow the steps below so that you can gain confidence.
The steps you might consider are as follows:
- What inputs does your program need? First, get your program
to accept those inputs and print them out so you can see they are
set properly.
This means that you should type in the code to prompt the user for
the input(s), print out the values of those inputs, and that's all for now.
Run your program at this point and make sure it is behaving as you
want.
What inputs do you need? There's no reason to ask for more than is
necessary. At a minimum, you have to know how many rounds of RPS to play
before printing the resulting statistics.
- Next, create a loop that simply iterates the desired number of times.
Again, run your program. You may want to print something out in your loop
so you can verify that the loop works correctly.
- You next can make the concept of the random player real.
This means declaring a variable name of a suitable type to represent
this concept, establishing the variable's
initial value.
What is the concept of the player? There are many details about the player
that appear unnecessary: the player's name, address, cell phone number.
On the other hand, if we are going to play RPS, we need to know what
move the player has made. This is the important concept.
How do we represent the choice of rock, paper, or scissors? This is left
up to you, so try for something simple. It may help to recall how Paul
Revere was
(poetically)
told of how the British were coming: one if by land, two if by sea.
In otherwords, an int encoded the manner of invasion.
If there were only two choices, why didn't Paul use a boolean?
Sadly, Bool was not yet born.
- In your loop, you should modify this variable's value to reflect
the associated player choosing randomly
among rock, paper, and scissors each iteration.
You've seen how to use the random number generator to pick between two
outcomes. Now you must pick between three.
- Run your program and verify that the player is choosing randomly.
- OK, now for the other player. This player must cycle among
rock, paper, and scissors. Let's make this player real by declaring a
variable name of a suitable type and establishing its initial value.
In the interest of consistency and simplicity, you should use the same
encoding for this player in terms of what value means rock, what value means
paper, what value means scissors.
- In your loop, arrange for this player to choose its next move based on
its previous move. If the move used to be rock, it's now paper. If the move
used to be paper, it's now scissors. If the move was scissors, it's now rock.
- Run your program again and make sure the cycling player is behaving
properly.
To verify the cycling player's behavior, you will probably want to print out
the values representing that player's move each iteration.
It won't take many iterations to see if this is working or not: 10 should do.
- Each player has made a move; now let's see who won. First,
pick a name, type, and initial value for the number of wins a player has.
Do the same for the other player.
Why do we need a variable to keep track of each player's wins? Why not keep
track of only one player's wins and assume the other player won the other
rounds?
- In the loop, determine who won based on the current value of each
player's move.
Use the rules of RPS to adjudicate the winner, and credit
the win count properly.
- After the loop completes, report the fraction of wins awarded to each
of the two players.
- Test your code by trying it with just one iteration, two iterations, and
three iterations. Make sure it's working before you set it loose.
- Run your code several times, each on 1000 iterations.
- Based on what you see, did one player tend to win more often than the other?
End of extension 100


Scan QR Code from Image input
This example shows how to scan a QR code with ZXing javascript library from an image.
The example decodes from the
src
in
img
tag, however is also possible to decode directly from an url without an
img
tag.
See the source code for this example.


Though often used interchangeably, in biology these words have different meanings. Fish is used as a singular noun, or as a plural to describe multiple individuals from a single species. Fishes is used to describe different species or species groups. Thus a pond that contained a single species might be said to contain 120 fish. But if the pond contained a total of 120 fish from three different species, it would be said to contain three fishes. The distinction is similar to that between people and peoples.
In biology, the term fish is most strictly used to describe any animal with a backbone that has gills throughout life and has limbs, if any, in the shape of fins. Many types of aquatic animals with common names ending in "fish" are not fish in this sense; examples include shellfish, cuttlefish, starfish, crayfish and jellyfish. In earlier times, even biologists did not make a distinction – sixteenth century natural historians classified also seals, whales, amphibians, crocodiles, even hippopotamuses, as well as a host of aquatic invertebrates, as fish. In fisheries, the term fish is used as a collective term, and includes mollusks, crustaceans and any aquatic animal which is harvested The strict biological definition of a fish, above, is sometimes called a true fish. True fish are also referred to as finfish or fin fish to distinguish them from other aquatic life harvested in fisheries or aquaculture.
A random assemblage of fish merely using some localised resource such as food or nesting sites is known simply as an aggregation. When fish come together in an interactive, social grouping, then they may be forming either a shoal or a school depending on the degree of organisation. A shoal is a loosely organised group where each fish swims and forages independently but is attracted to other members of the group and adjusts its behaviour, such as swimming speed, so that it remains close to the other members of the group. Schools of fish are much more tightly organised, synchronising their swimming so that all fish move at the same speed and in the same direction. Shoaling and schooling behaviour is believed to provide a variety of advantages.
While the words "school" and "shoal" have different meanings within biology, the distinctions are often ignored by non-specialists who treat the words as synonyms. Thus speakers of British English commonly use "shoal" to describe any grouping of fish, and speakers of American English commonly use "school" just as loosely.


CSPICE_JYEAR returns the value for the number of seconds in a
Julian year.
Given:
No input required.
the call:
jyear = cspice_jyear
returns:
jyear the number of seconds per Julian year as a double precision
scalar.
[1,1] = size(jyear); double = class(jyear)
Any numerical results shown for this example may differ between
platforms as the results depend on the SPICE kernels used as input
and the machine specific arithmetic implementation.
>> jyear = cspice_jyear
jyear =
31557600
>> sprintf( 'JYEAR value: %11.3f', cspice_jyear )
ans =
JYEAR value: 31557600.000
None.
For important details concerning this module's function, please refer to
the CSPICE routine jyear_c.
MICE.REQ
TIME.REQ
-Mice Version 1.0.1, 11-JUN-2013, EDW (JPL)
I/O descriptions edits to conform to Mice documentation format.
-Mice Version 1.0.0, 22-NOV-2005, EDW (JPL)
Number of seconds per julian year
|