text:
Probably Done Before
What the Heck is Base64 Encoding really?
Also, Why most implementations of Crockford-base32 encoding are probably incorrect
TLDR: The term base64 encoding is an overloaded term which promotes ambiguous usage. It can mean either a place-based 64-symbol encoding of a single number, or a streaming algorithm for encoding an array of octets. In common usage, it is the latter -- the same technology and IETF RFC specification that allows us to encode arbitrary binary files and place them in USENET posts and emails.
Examining the differences between the two meanings and two implementations will teach us something about ambiguity, online/stream algorithms, and that specifications are really really very important.
TLDR: The Crockford-base32 encoding proposal, as written here http://www.crockford.com/wrmg/base32.html, is not as clear as it could be and lacks a canonical implementation and/or test-cases.
This lack of clarity has lead most people to interpret it as a place-based 32-symbol encoding of a single number. However, the particular wording and context of his proposal implies that the Crockford-base32 encoding was meant to adhere closer to the existing base64 and base32 octet binary encodings (including padding of binary data up to a multiple of the 5-bit space).
The Presence of An Ambiguity
I want to use this post as a way of clearing up a confusion that seems to exist in many people's understanding of base64 (and also crockford-base32).
Because on ambiguity exists, I am going to invent my own clarifying terminology (Place-Based Single Number Encoding versus Concatenative Iterative Encoding) to attempt to disambiguate. Along the way, we will get into the nitty gritty details of binary base64-encoding (as commonly implemented in a thousand different systems) and of the radix-placed system that most people are taught as binary, octal, decimal and hexadecimal numbers.
But before I do that, let me explain what the Crockford-base32 encoding is meant to do, for those of you who have never heard of it.
Human Readable URLs
Producing URL shortening and youtube-like resource strings seems to be the raison d'être for the Crockford and other such encodings. Many famous web applications have something like this: a unique string of letters and numbers that when used within a URL/URI, provide a unique and identifying name for that resource. Resource examples range from videos, to shortened URLS, to collabedit pages, to flickr accounts.
With all these services, we desire to provide a unique identity to a resource whose cardinality may grow into the millions or billions. Certainly, the identity could be something as simple as an integer increasing in value (what the database guys call a sequence). The drawback with a sequence is that it provides people a way to guess resource identities. To counter this, we could generate a random number with insignificant chances of repeating (and of guessing) and encoding it in a high-radix encoding to shorten its string-length.
Let's examine two ways to do this.
Radix Place-Based Single Number Encoding System
This system is the easier of the two to explain, as it is covered in most high-schools, and CompSci 101. Nevertheless, we will go through it again.
We start with the number 101.
What is this number? Is it the number of dalmatians that should be brutally murdered, skinned, and fabricated into a woman's coat? Or is the cost of a 5 dollar foot long?
The answer is that it could be either. The number is the ultimate abstraction, that which your brain interprets, and the glyphs and the symbols are the permanent memory of that number on paper or on disk. But in-between, we need to apply a decoding to turn interpret the glyphs from symbols through numerals to a number. In binary, the glyph/symbol/numeral string of "101" can be interpreted as "five" -- just enough dollars to buy a Subway sandwich. In decimal, which most humans (without compsci/math background) take for granted, the string "101" is interpreted as "one hundred and one."
The term radix, which is synonymous with the term base, is defined as the number of unique symbols in a place-based numeric system. The radix-system that most humans use is a base-10 or radix-10 system. The symbols we have today for our numbers came to us during the Renaissance from the Arab mathematicians. We called them arabic numerals, despite the fact that the Arab mathematicians imported them from the Indians who invented the numeral 0. This special numeral 0, along with the other nine symbols, make up the most famous and consistent symbols that the world has ever seen. We all collectively own these symbols today: '0', '1', '2', '3', '4','5','6','7','8','9', and we assume that they are in this order: 0123456789.
To restate, the reason that we call this a radix-10 system is because we have 10 unique symbols. However to be a base-10 system, we do not have to use these exact symbols or in this traditional order. How weird a parallel universe there must be where, due to a transposition error, our system could have been 0123465789? Fifty would be "60."
Place-Based Systems
Why are the numbers made from these symbols (of any radix) called place-based systems? The answer comes from the fact that every numeric representation is a string where the place represents a power in that radix from right to left.
As you can see above, the simple decimal number 1853 has four places:
farthest to the right, the ones place 100
second to the right, the tens place 101
third from the right, the hundreds place 102
and fourth from the right, the thousands place 103
and the string '1853' is thus a representation of a number using places to indicate powers.
A famous example of a numeral system that is not place-based is the Roman Numeral system. A Place-Based System applies not just with decimal, but with all the radix-based systems we see below.
Binary Place-Based Single Number Encoding System: 01
Standard coursework tells us of binary, a radix-2 system using (by definition) two symbols: '0' and '1'. In this base, the number 1 is '1', the number 2 is '10', the number 3 is '11', etc. This is the numeral system of computers and disks that provides the unifying clutch between voltage and symbolic logic, truth, turing machines, and computation.
Octal Place-Based Single Number Encoding System: 01234567
If we have a base-8 system, we can only use eight symbols. Reusing our first eight symbols from the base-10 system we get: 01234567. In this base, the number seven is 7, but the number eight is 10 because we have run out of symbols. We call these octal numbers. We should call them octal numerals.
Hexadecimal Place-Based Single Number Encoding System: 0123456789ABCDEF
And what if we have more than 10 symbols? Hexadecimal, a base 16 system, is a good example of one. We commonly choose to use some letters from the latin alphabet (whether capitalized or not) as the 6 remaining symbols. Thus our alphabet of symbols in order is : 0123456789ABCDEF. In this base, the number 15 is F, and the number 16 is 10. Most people are familiar with hexadecimal numerals usage in RGB values.
Tetrasexagesimal Place-Based Single Number Encoding System
For base64, we can use the lower-case alphabet and the upper-case alphabet: abcdefghijklmonpqrstuvwxyz and ABCDEFGHIJKLMNOPQRSTUVWXYZ. But this only gives us 26*2= 52 symbols, and we need 64 symbols. The symbol alphabet of numerals 0123456789 gives us ten more for a grand total of 62 symbols. We need to add two more.
For now, let's just choose the plus symbol '+' and the slash symbol '/'. Because we can order these symbols in any order we want, how about the following ordering?
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w
15 P 32 g 49 x
16 Q 33 h 50 y
In this base, the number seven is 'H', the number 50 is 'y', the number 62 is '+', and the number 64 is 'BA'.
But now, here is the big question: Is this the same base64 encoding that was used to pass binaries and dirty images on USENET posts? Is this the base64 that most languages, browsers, and email-clients support with library functions? Is this the base64 of RFC 4648?
The answer is a big fat NO. To explain why is not the same thing, we will make a digression and consider the notions of functions and types.
Functions and Types, Domains and Ranges
Types and functions are utterly fundamental to the art, science, and craft of programming.
One might say that types allow us to think about data, while functions allow us think about computation. Functions and types come clothed in different syntactical and run-time forms in any of your favorite language, but they are omnipresent and never to be discounted.
So why are we bringing them up? The answer is because we they will be helpful in explaining the difference between Place-Based Single Number Encoding and Concatenative Iterative Encoding.
Up to now, we have been describing the notion of radix and base to represent a number, a system that we called Place-Based Single Number Encoding. To help us understand this encoding, let us describe it as a function with an input and an output.
A representation is nothing more than a string of symbols in some alphabet.
Thus, the number 101 is the decimal representation of the number "one hundred and one" while 65 is its hexadecimal representation. Both 101 and 65 are strings of symbols.
This is simplistic, but really exposes the essence of what we have been doing thus far. When we wanted to convert a single number into a binary representation we implicitly knew that the Domain of our function (our input type) was that of a number, and that the Range (the return type) was that of a string of zeros and ones. We can denote this function signature like this:
Ok. It feels like we burdened the obvious with theory. How does this help explain what email-based base64 encoding is? Well, the answer is to show the difference in their function signature, types and all.
What the base64 encoding of RFC 4648 does, and why it is different, is this:
It iteratively consumes an array of octets, transforms them into Base64 representations, and concatenates each representation into an output array.
In conclusion, we are saying one way of seeing the difference between these systems is by comparing their signatures
Place-Based Single Number Encoding
Concatenative Iterative Encoding System
Does that clear it up?
Yup, the term Concatenative Iterative Encoding sounds like a lot. But if we look at each word and examine its function signature, we will find it to be a description that is succinct and accurate.
Let's dissect both the term and the function signature, using the following visual of a file to motivate.
What we see above is a file (any file) represented as a long tape of zeros and ones. I have purposely colored four different groups of octets. Grouping bits into 8-bit chunks, called octets or bytes, makes it easier for us to think about the sheer number of zeros and ones. All files, whether text or not, are ultimately a concatenation of bits, so this is a valid way of understanding a file.
We can imagine the encoding function as a box that iteratively works its way down the tape, turning octets into base64 atoms. As the box/function moves its way down the tape, it slowly builds up the output tape by concatenating newly encoded base64 atoms. We are iteratively consuming octets from an array [OCTET] and concatenating them onto an output array of base64 representations [BASE64_REPRESENTATION].
The implementation details of how we transform octets into numerals from a base64 are actually quite simple. I will go through them now, but the following sites provide more exhaustive descriptions:
The wikipedia page
Computer science in JavaScript: Base64 encoding
We start with a stream of octets which means that we are grouping a stream of binary bits by 8 bits each.
As you can see above, by merely choosing to put a grouping marker between every 8-bits, we can interpret this stream of 24 bits as 3 octets. Furthermore, we can choose to interpret each octet as the decimal numbers shown above, thus we see the numbers 77, 97, and 110. This example comes from the wikipedia article, showing how a text input could have been encoded, where the ASCII values for the word 'Man' are the input octets -- in ASCII 'M'=77, 'a'=97, and 'n'=110.
So what does base64 encoding do? Does it transform the input at all? No. It merely adjusts the grouping markers. Where before we grouped by 8 bits, now we will group by 6-bits.
As you see above, we have reinterpreted 24-bits of data as 4 groups of 6-bits (sextets) rather than 3 groups of octets. Again, putting a decimal number for these new groups, we see the numbers 19, 22, 5, 46. But remember that base64 symbol table we had above? I will copy it down here again:
As we look at it, we can assign the number 19 to the base64 encoded numeral 'T', 'W'=22, 'F'=5, and 'u'=46. Thus,
a text file with the ASCII contents of 'Man' will result in a base64 encoding of 'TWFu'.
Summing it all up
The Concatenative Iterative Encoding System has the following signature,
which in our particular example looks like:
or equivalently
And that is it. That is what base64 encoding does. It groups a stream of binary bits (grouped in 8-bit chunks) into a stream of output 6-bit sextets. Each sextet is interpreted as a single symbol from the radix-64 alphabet, and re-emitted as the ASCII representation of that symbol.
Is it Compressions? No.
There always seems to be a major misapprehension of base64's purpose, and one that we should try to clear up right now.
Base64 Encoding as a Concatenative Iterative Encoding System permits an arbitrary binary file to be translated into a string of text and copied in an email, or posted in a Usenet post. We have protected higher-level applications (like MIME) from arbitrary binary by choosing only letters that can exist within that application's specification.
We have compressed the string length of symbols but we have not compressed the overall data size. In fact, we have actually inflated the size of the overall data payload by re-embedding the string 'TWFu' using ASCII.
Let us repeat the last statement: base64 does not compress the input data. In fact it inflates the size. It only compresses the length of the symbol string, by using an alphabet with more symbols.
A Final Comparison
Single Number
Array of Octets
representation of number in different radix
Array of Base64 representations
Consumption Direction
Representing a single number in a different radix, using a different alphabet consisting of different symbols.
Turning arbitrary binary into a left-to-right array of encoded characters that may be embedded and transferred within the context of an applications.
In the above chart there is one term that we have not yet discussed called "Consumption Direction". The point of this is to show that Place-Based Single Number Encoding works on an entire number whose place-based format requires knowledge of the rightmost digit. To put it another way, you need to know the farthest right-most bits before you know what the number is.
On the other hand base64 as a Concatenative Iterative Encoding System consumes binary data from left to right. The reason for this is that base64 encoding usually operates on files which cannot always be loaded into memory. This is why we have subtly been referring to this algorithm as a streaming algorithm -- it does not have access to the entire input, but may start generating the output with only the first three octets. The actual physical implementation of reading bits from disk means that we always have access to the most significant bits (leftmost) before the least-significant bits (rightmost) are event loaded from disk.
The Place-Based Single Number Encoding is not appropriate for encoding a file because you would
need to load the file into memory to know its numeric representation
the number would be HUGE
On occasion, the two systems will produce the same answer. These occur when the number is bit-represented in multiples of 3-octets. If the number is slightly more than 3-octets, or only 2 or 1 octet, then the base64 specification calls for something called padding which adds zeros to the rightmost side. The effect of this is that base64 respects the leftmost/prefix data, while allowing the rightmost to be vastly different.
Padding is one of our hints that we are dealing with a streaming algorithm.
Finally, An Analysis of Crockford-base32 and its Implementations
The Crockford-base32 implementation has a few desirable properties that I will copy directly from the website:
The encoding scheme is required to
Be human readable and machine readable.
Be compact. Humans have difficulty in manipulating long strings of arbitrary symbols.
Be error resistant. Entering the symbols must not require keyboarding gymnastics.
Be pronounceable. Humans should be able to accurately transmit the symbols to other humans using a telephone.
Additionally, it tries to remove accidental obscenities and ambiguous looking symbols (like 0 and O).
I needed a Crockford32 implementation for Erlang but could not find one, so I looked up various implementations in other languages to try to understand what they did. I also looked closely at the base64 implementation that comes with the Erlang runtime. It was then that I figured out that the Crockford32 implementation implies Concatenative Iterative Encoding System but that all the implementations I could find are Place-Based Single Number Encoding.
The Conflicting Evidence
Evidence for thinking Crockford32 was meant to be a
All implementations use this assumption.
Zero implementations use this assumption.
The quote from the website saying,
"This document describes a 32-symbol notation for expressing numbers in a form that can be conveniently and accurately transmitted between humans and computer systems."
Emphasis mine.
Quotes from the page that compare it in context with other Concatenative Iterative Encoding Systems
"Base 64 encoding uses a large symbol set containing both upper and lower case letters and many special characters. It is more compact than Base 16, but it is difficult to type and difficult to pronounce."
"Base 32 seems the best balance between compactness and error resistance. Each symbol carries 5 bits."
Language that implies that the primary use-case for this encoding is Human consumption which means short strings.
Short strings do not require streaming algorithms, as an entire number can absolutely be loaded into memory:
The most damning quote of all:
"If the bit-length of the number to be encoded is not a multiple of 5 bits, then zero-extend the number to make its bit-length a multiple of 5."
This quote is absolutely about padding enough bits to the rightmost digits.
In the end, I think this has been a nice learning experience for me, and hopefully something worth sharing. Importantly, it drives home a few points:
most base32/16/64 encodings were designed to be streaming algorithms and operate only on octets and usually on a dataset that would not fit into memory
the recent explosion in services that want short-URLs while having unique identities for resources have increased the need for non-streaming radix-encoding algorithms
specifications are very important. The Crockford32 page is ambiguous, especially in comparison with the base64 specification which even includes test cases
Finally, here is an Erlang implementation I wrote for Crockford-32 as a Place-Based Single Number Encoding.
Posted by Daniel Eklund on Sunday, April 27, 2014
Nice write-up.
What a horrible theory!
Your evidence for Crockford32 being a Concatenative Iterative Encoding System is completely unconvincing.
When Crockford talks about base64, he explicit refers only to the "symbol set" it "uses". No comparison is made with the standard as a whole.
"Base 10 is well known and well accepted" is also obvious proof that this is a scheme to encode integers and not arbitrary data. There is no well-known standard for transmission of binary data in base 10, as it would be computationally very expensive. However there is no doubt that people use base 10 all the time to encode integers!
Your interpretation of "zero extension" to mean padding the rightmost digits is also flawed. It's the unsigned counterpart to "sign extension", and it is extremely common: for example the x86 has a dedicated MOVZX instruction to perform Zero eXtension (by padding the leftmost digits).
If you want to contradict the clear and unambiguous statement that "This document describes a 32-symbol notation for expressing numbers", you should have better evidence than that. You're the only one to think that the standard is ambiguous in that regard. But I do agree that test vectors would be nice, and I would add that endianness should have been explicitly mentioned.
Daniel Eklund April 28, 2014 at 7:05 AM
A "horrible theory", like my use of the word "incorrect" might be a bit harsh, but I do appreciate your passion.
I don't advance my interpretation with 100% certainty, and I feel like I was honest enough to present a table showing evidence for both sides. The ambiguity was the frustrating part, not any belief that implementations were "incorrect".
Your point about base10 is well-taken and does give me pause.
However, I want to push back about the padding argument. Since neither left nor right padding was mentioned, the ambiguity remained. I reasoned thusly:
Why would you need to pad non 5-bit multiples to the left?
This argument is key. The quote from the page is this: "If the bit-length of the number to be encoded is not a multiple of 5 bits, then zero-extend the number to make its bit-length a multiple of 5."
As an example, take a 32-bit (4-octet) number, like 01100001011000010110000101100001 (which in decimal, is 1633771873). This is NOT a multiple of 5-bits.
Why, just because it is not a multiple of 5-bits, should I zero-pad it to the left with 3-more bits, or 8-more bits?
Left-based zero padding, DOES NOT CHANGE THE VALUE OF THE NMUBER at all.
crockford32NumberEncoding(01100001011000010110000101100001) --> "1GP2RB1"
crockford32NumberEncoding(0000000001100001011000010110000101100001) --> "1GP2RB1"
The statement from the page,
"If the bit-length of the number to be encoded is not a multiple of 5 bits, then zero-extend the number to make its bit-length a multiple of 5"
is quite a strong statement of the form: "If then ". I can't believe it was made with the knowledge that the action has no impact whatsoever, otherwise it is completely irrelevant and can and should be removed.
If padding to the left does not matter, then all that remains is padding to the right, which DOES matter. It was actually this sentence in the specification that gave me pause as I was familiar with how base64 encoding right-pads and inserts "==" in the output string as indication of the padding.
If we right-pad, we get
crockford32NumberEncoding(0110000101100001011000010110000100000000) --> "C5GP2R80"
and "C5GP2R80" != "1GP2RB1"
I don't know what Douglas Crockford meant the specification to REALLY be. I would love him to find this page and answer. Most people interpreted it as a base32-radix encoding with a single number. Me too.
Sorry for the strong words, I saw it on Hacker News where the title was "Why most Crockford32 Implementations are Wrong". The hubris of this statement made me overlook the more tentative wording of the post.
"Left-based zero padding, DOES NOT CHANGE THE VALUE OF THE NMUBER at all."
And it's exactly the reason why it's chosen! Padding the shortest binary representation of a number to the left introduces no ambiguities, since the first digit is always a 1 (for non-zero numbers), whereas padding to the right would make decoding ambiguous ("10000" could correspond to 1 or 10 or 100...).
Of course padding is only necessary if you start from a binary representation of the number and want to transform it into a base 32 representation. You don't need it if you compute the base 32 representation from scratch:
1100001011000010110000101100001 (base 2)
= 1GP2RB1 (base 32)
= 00001 10000 10110 00010 11000 01011 00001 (base 2)
where you see that zero-extension to a multiple of 5 bits has happened naturally. I'm guessing that's why you find this mention of padding unnecessary: it's just that it was written with binary representation as a starting point.
And that kind of padding is completely different from base64's padding with "=" symbols, which aims to let you concatenate different blocks of base64-encoded data. It doesn't make sense to concatenate numbers, that's why Crockford32 goes as far as using "=" for a completely different purpose. If it was an alternative to base64, it would have been wise to at least keep the option of base64-style padding open!
Daniel Eklund April 28, 2014 at 12:16 PM
Respectfully, I am not understanding you point here.
It seems you are agreeing that padding to the left does not change the number (and very importantly here, we are talking about bit representations of integers in an unsigned schema, since nowhere have we opened the can of worms that is 1's-complement or 2's complement for negative numbers).
I completely agree with your statement, "Padding the shortest binary representation of a number to the left [with zeros] introduces no ambiguities" as that was exactly my point, but I take it further and say, "zero padding to the left introduces no ambiguities, but there were no ambiguities to be introduced in the first place".
You gave me the number: 1100001011000010110000101100001
It is 31 digits long. Its decimal representation is 1633771873. I feel no ambiguity in understanding what number it represents -- and yet it is not a multiple of 5-bits. Why do I need to pad four extra zeros to the left (35 bits now), to make it a multiple of 5? Why is Crockford-32 telling me I should zero-pad?
As such, I am still left with this question about the Crockford 32 specification:
If left-padding was implied, why does the sentence,
have to exist at all? What does it add to the discussion regarding implementation?
If it adds nothing under a left-zero-padding assumption, then it is irrelevant and should be removed. Would you agree with that?
But since it is present, I take its very existence to mean something. Especially since in _most_ base encodings, the implementation of padding is meant to line up the N-bit-space with the 8-bit (octet) unit of data storage in all files, and is always right-padded.
I believe that the very presence of this sentence is probitive of a "Concatenative Iterative Encoding" interpretation.
I would prefer the specification be re-issued with these ambiguities removed.
I see no reason to not have both: 1) a specification for encoding a single number, and 2) a specification for a data encoding that operates on octets and must be zero-padded to the right if the final bit count is not a multiple of 5 and 8 -- like regular base64, base32, or the Zooko-base32 encoding.
Likewise, it would be neat if people acknowledged the differences when they were teaching base64 as ONLY "Concatenative Iterative Encoding". As an example of that is this blog post
http://code.tutsplus.com/tutorials/base-what-a-practical-introduction-to-base-encoding--net-27590
where the author starts with a "Place-Based Single Number Encoding" interpretation until he gets to base32 and base64 at which point he switches to a "Concatenative Iterative Encoding" interpretation.
"You gave me the number: 1100001011000010110000101100001
It is 31 digits long. Its decimal representation is 1633771873. I feel no ambiguity in understanding what number it represents -- and yet it is not a multiple of 5-bits. Why do I need to pad four extra zeros to the left (35 bits now), to make it a multiple of 5? Why is Crockford-32 telling me I should zero-pad?"
Your process in obtaining 1633771873 was the following:
representation in base 2 "1100001011000010110000101100001"
abstract mathematical integer
representation in base 10 "1633771873"
You're using algebra (multiplications, divisions) to convert back and forth to the abstract mathematical integer. It's the only way to do it, because 10 and 2 are not powers of some common radix, that is, log 10 / log 2 is irrational.
But, if you want to convert it to base 16 or 32, there is another way:
padded representation in base 2 "00001 10000 10110 00010 11000 01011 00001" (the spaces are here just for clarity)
representation in base 32 "1GP2RB1"
Here, each step is simple, local, and involves no algebra: the first step pads to a multiple of 5 bits, and the second step is just a lookup of the symbol corresponding to each group of 5 binary digits. The reason you need to pad to a multiple of 5 bits is simply that you couldn't do the lookup if you couldn't split the binary string into groups of exactly 5 bits!
I can't read minds, but I think Crockford simply wrote the specification with the mental model of the second process. He just didn't write down the lookup step.
DomFilk September 23, 2015 at 1:17 AM
Jakob Petsovits December 21, 2015 at 4:24 PM
I find it shocking that all of these library authors would find it intuitive for hex (base16) and base encoders to have an API like encode([octets]) but for base32 a much more limiting encode(number) would make more sense.
I guess this leaves us with fundamentally two different Crockford base32 standards, streaming and numeric? Maybe someone feels compelled to advertise a clarified spec with both of these as sub-codecs. Crockford fixing his web page would be nice but maybe enough harm has been done that a better way would be to accept that both are reasonable and already implemented viewpoints. We might be better off just documenting them both instead of figuring out which one is "correct".
Thanks for the article! At least that cleared up why my work-in-progress (stream) implementation doesn't match the output of some other libraries for even a single low number/byte.
George Kelly January 5, 2021 at 1:02 PM
We are an independent organization with a penchant for streaming device products and activation. Our team is well trained in every single aspect of the Roku's working and they can sort out any issues you face with the Roku. Feel free to talk with our experts through the toll-free number +1-805-697-0100 and frame the finest alternatives. Before you contact us, kindly refer the setup guide and solve off the hassles in a short time. Perform the system reset process and also do not forget to activate the device using the roku.com/link/activate roku / go.roku.com/channelsignup / roku.com/link create account device
Nick Smith January 5, 2021 at 10:18 PM
Southwest Airlines support Number
Southwest Airlines Booking Number
Southwest Airlines Reservation Number
Southwest Airlines Cancellation Number
Southwest Airlines Manage Booking
Spirit Airlines Support Number
Spirit Airlines Booking Number
Spirit Airlines Reservation Number
Spirit Airlines Manage Booking Number
Spirit Airlines Morning Flights
Frontier Airlines Booking number
how to get cheap flights
where to find cheap flights
Frontier Airlines Reservation Number
Frontier Airlines Reservations
Etihad Airways, Etihad Airways Cancellation Number, Etihad Airways Cancellation Policy, Etihad Airways Manage Booking, Etihad Airways Refund Policy
Delta Airlines Cancellation Number
Alaska Airlines manage booking
Alaska Airlines Reservation Number
jetblue airways manage booking number
American Airlines Booking Number, American Airlines Support Number, American Airlines Reservation Number, American Airlines Cancellation Number, American Airlines Manage Booking
QuickBooks Customer Service January 8, 2021 at 3:54 AM
Keep it up and i am glad to read your blog today.
QuickBooks Customer Service Support offers a comprehensive range of QuickBooks error resolution services in the hour of need. In case of any further information related to Common QuickBooks Pro Errors, you can Dial Toll-Free Number. Our team is available to guide you round the clock and we will never disappoint you in any case.
kraigsmitham January 9, 2021 at 1:53 AM
At first, you need to get the link code on the TV screen by setting up the Roku device. After getting the link code, you need to go to the Roku.com/link activation page using a browser. In there, key in the Roku link code without any mistakes. Moreover, sign in with the Roku account using the Roku credentials. Finally, refresh the Roku screen and start with the channel installation process
Daniel Eklund
I am 20 year programmer/consultant with a background in enterprise software engineering and big data. This blog is my place to keep up with my love of functional programming languages, and foundational mathematics. Recently, I've been creating a site from Erlang, Elixir and Haskell, called Wordadoplicus -- a site for old-school boggle-type real-time word games.
Why the Heck is Git so Hard?
Why the Heck is Git so Hard? The Places Model™ … ok maybe not hard , but complicated ( which is not a bad thing ) This post is ai...
Visualizing Docker Containers and Images
This post is meant as a Docker 102 -level post. If you are unaware of what Docker is, or don't know how it compares to virtual machi...
What the Heck are Algebraic Data Types? ( for Programmers )
This post is meant to be a gentle introduction to Algebraic Data Types. Some of you may be asking why you should learn Algebraic Data Typ...
The Occultation of Relations and Logic: Exposing the Hidden Meaning from within Shadows and Unix Command Lines
Here is a question and answer stolen from another website : " I have [an] nginx log file, and I want to find out market sha...
What the Heck is a Relation? From Tables to Cartesian Products to Logic
Awww... I have given several talks and courses on Apache Hive and Pig and other new-ish 'Big Data' languages built upon Hadoop an...
Also, Why most implementations of Crockford-base32 encoding are probably incorrect TLDR : The term base64 encoding is an overload...
Animating the Git Branching Model: Part 1
I've been trying to learn Apple Motion 5. In my day job, I draw a lot of architecture diagrams to communicate with clients and with my ...
Gotcha with Bitstrings in Erlang: Naked Chevron Numerals are Decimal
Some Confusing Erlang Bitstring Syntax or how "A" is 01000001 in decimal and binary TLDR Summary <<0100000...
Erlang Radix Syntax, and Lambda as the Ultimate Meaning
Follow Up to "Gotcha with Bitstrings" How to ACTUALLY denote binary numbers in Erlang After I put the previous post together, I...


text:
Dirty Jack Slot Game Review
Good news is that it requires no download and no registration, so that everyone can play this PariPlay free online casino slot effortlessly here at Slotopus as well as other games by this provider. With a mouth-watering selection of online slot machines and many progressive jackpots waiting to be won, this gambling site is certainly worth a punt, especially considering the fact that new players can claim up to 600 in welcome bonuses with 80 free spins . With more than 200 slot machines available to play, the Wink Slots Casino lobby is bound to hold something for everyone. No matter whether you are into big action 5-reel video slots, simple retro classics or something in-between, there should be something to satisfy your spinning desires thanks to a wide variety of slots on offer from NetEnt, WMS, Lightning Box, Eyecon Gaming, IGT, and even 888's very own game development team. Sometimes it doesn't really matter what kind of game you play, as long as there is a chance for some big wins. Luckily, Wink Slots Casino stocks a great selection of progressive jackpot slot machines, from retro style games like Saved by the Bells to exciting adventure video slots such as Pirates Millions Jackpot and Treasure Fair. Since they've been in business, Simbat have released more than 200 titles relating to either online slots, casino or bingo, their areas of speciality. Turbo Reel is just the latest in a long line of slot games which deliver the arcade experience into the online environment. At other times not only do you get to try a fabulous new slot, but you also have a chance to snatch great prizes while doing so. To celebrate the launch of NetEnt 's fantastic new slot Fantasini: Master of Mystery , one of the most entertaining online casinos , LuckyDino Casino , promises players Free Spins a day early. The Alchemist's Gold video slot, therefore, is a perfectly apt theme for online slots fans, as we are all looking for a great real cash benefit from an entertaining game. Overall, though an RTP of 96.02% should offer a decent return over time and gamblers are recommended to test the game here in our play for free version. The Alchemist's Gold video slot has a tantalising promise of top prizes up to 80,000 coins for the lucky gambler.
It's not all fun and game, however, because this online casino does lack a very important thing live chat. VISIT CASINO With no live chat and a small amount of FAQs available to browse through, players will have to search through the long terms and conditions if they are going to find anything out about the banking options at this casino. The smallest deposit accepted by Wink Slots Casino is 10, while there are maximum limits of 1,000 per day, 3,000 per week and 5,000 per month. As for withdrawals, customers are restricted to maximum payouts of 1,000 per day, 2,000 per week and 3,000 per month. Those who grew up with the old school style slots will love everything about this game, including the nine familiar symbols which as the plums, melons, cherries, lemons, oranges, horseshoes, stars, lucky 7s and diamonds and all of these can make an appearance as either a single or double symbol.
Kick off with a £600 Bonus
That is because this bonus for new players is worth up to 600 in deposit bonuses over the first three payments, like so: On top of that, the casino will add a total of 80 free spins over these three deposits. This game is open to real money slot machine players at B & M or online. However, most players usually choose Free Play so that they can first understand the game better and then wager real money on it. The good thing about Cozino online casino is that theres a long list of payment methods you can use to deposit and withdraw money to and from your account. The casino accepts some pretty rare deposit methods that are popular in Eastern Europe and welcomes deposits and withdrawals in RUB, so its clear that its trying to attract customers from this part of the world.
Come in, Cowboy, and be Ready to Win
The paytable is placed above the grid and describes the symbols and their values. Before you start to play Dirty Jack free slot machine you are to complete the bet settings. It is this symbol that wins the jackpot when playing at maximum bet. Dirty Jack casino slot machine has got the interface that can make any player glad.
Other Slots Worth Checking Out
This is a simple fruit-based slot, but like Time Bender it's reliant on what happens on its game board rather than any bonus features built in. Indeed, the reason why the closest slots to Time Bender in terms of gameplay have substantially less paylines is because this Arrow's Edge game behaves in a manner more akin to that of a basic old school slot – nudges, after all, are one of the oldest fruit machine features in the business.
Wink Win Casino
Wink Win
Get your bonus €200; Match: 100%
NetEnt , view , Thunderkick , Microgaming , games

redpajama_set_name: RedPajamaCommonCrawl


See how we brought the story of one of the oldest working Flour Mills in the US to life through featured video content and a custom built website.
We work with the Dietrich family apple farm located right here in West Michigan. Our cider is never ... Vander Mill Grand Rapids Opening – check out the video!
12 мар 2014 ... Мельница Эликор в работе ... Sign in to add this video to a playlist. Sign in. Share ... Rating is available when the video has been rented.
Mill Valley Emergency Preparedness and Evacuation Planning. When disaster strikes ... We've got work to do and we want you to be a part of it! Read More.
This video presents Greenpac Mill, a recycled linerboard mill based in Niagara Falls ... manufacturing processes and high performance work organization.
The Veirs Mill Corridor Plan extends approximately four miles, from the City of Rockville to the ... Work Session ... View Presentation | View Staff Report | Video.
Sep 3, 2018 ... A new miller has been found to produce flour at an historic mill after the ... Simon Dodd is to start work at the 17th Century Worsbrough Mill, ... Man wanted over Sheffield murder urged to 'think of victim's mum', in video appeal.
Why Work in Mill Creek. An image of the golf course in Mill Creek Creating Community Originally developed as a golf course community, Mill Creek is exceptionally well-planned and has managed to retain much of its small ... Video Tour Logo.
This article describes with audio and video the lifestyle and working conditions of linen mill workers in Ulster.
Best Friends puppy mill initiatives focus on stopping puppy mills. ... them a thing of the past. For more about life in a puppy mill, check out this eye-opening video.
We were lucky enough to grab a few minutes with Sid, co-3D Lead Artist, to talk about The Mill's awesome work on this beautiful music video.


The relation field is used to highlight connections to other records in the BCI.
For documents, it can relate to enclosed records, to multiple part articles.
For organizations, it can point out predecessor or successor organizations, or provide a link to a parent or list of child organizations.
For people, it can relate spouses, children, parents and other connections. It can also be used to provide information about images attached to the identification.
For laws, it can relate the law that superceded the one described, or preceded it.
Provide the relationship and use the use HTML opetin to add a link to the Public view of the item in the BCI so that the reader can click on the link to get to the related item.
On identifications, you can also link to information on the photograph attached.
John Guy was married to Gerda Sebbelov Guy.
This letter was enclosed in How-Martyn to Sanger, October 8, 1931.
[person] For photograph, see http://www.estelnegre.org/anarcoefemerides/2908.html.


North Korea has at least eight industrial facilities that can produce chemical agents; however, the production rate and types of munitions are uncertain. Presumably one or more of the agents [sarin, tabun, phosgene, adamsite, prussic acid and a family of mustard gases] comprising the basis of North Korean chemical weapons are produced at the Sinuiju Chemical Fiber Complex, probably including blood agents.
Military factories are classified as armament factories, which produce weapons such as firearms and munitions, general military factories, which produce general military material such as military uniforms and footwear, and those general machinery factories that can be converted for weapon and parts production during wartime. General military factories are located in the industrial district of Sinuiju while most wartime conversion factories are located in the industrial district of Pyongyang.
The Third Seven-Year Plan emphasized synthetic fiber production based on indigenous technology using coal and limestone, and on the production of chemical fiber based on petrochemistry. The government called for accelerating the expansion projects at both the Sinuiju and Ch'ngjin chemical fiber complexes. The textile industry, the most important light industrial sector, utilizes primarily locally produced synthetics and petrochemically based fibers, as well as cotton and silk. P'yongyang, the site of the P'yongyang Integrated Textile Mill, is the country's textile capital, but Sinuiju and Sariwn have been gaining in importance.


text:
Q: lua string.find can't match "/" Lua string.find can't find "/" in a reverse way of find, look at the following code:
c="~/abc.123"
print(string.find(c,"/",-1,true))
This always returns "nil"

A: Please refer to the Lua reference manual.
https://www.lua.org/manual/5.3/
string.find(c,"/",-1,true)

The third parameter of string.find will determin where to start the search.
As you entered -1 you will start at the last character of your string and search forward. Of course you won't find anything that way.
For strings positive indices give a position from the beginning and negative indices give a position from the string's end.
Use 1 to start from the first character. Then you'll find your slash. Alternatively you could use anything <= -8
Please note that you could also write c:find("/",1,true) as a shorter version.

A: To find the last occurrence of /, use string.find(s,".*/"). The second return value is the position of the last /.

A: Lua can't do leftwards searches, consider reversing the string first:
function Find_Leftwards(s,m,i)
    local b,f = s:reverse():find(m, i)
    return #s-f, #s-b
end

A: string.find cannot be used to do a leftwards search of a string. The init parameter merely sets the position from which to begin a rightwards search:

A third, optional numeric argument init specifies where to start the search; its default value is 1 and can be negative.

And an earlier note from the manual on negative indices:

Indices are allowed to be negative and are interpreted as indexing backwards, from the end of the string. Thus, the last character is at position -1, and so on.

You'll need to roll your own function which searches for an index starting from the right:
local function r_find (str, chr)
    local bchar = chr:byte(1)

    for i = #str, 1, -1 do
        if str:byte(i) == bchar then
            return i
        end
    end
end

print(r_find('~/.config/foo/bar', '/')) --> 14

Or consider using string.match to find the last section:
print(('~/.config/foo/bar'):match('/([^/]+)$')) --> 'bar'

Another option would be to simply split the string into its individual sections, and get the last section.

redpajama_set_name: RedPajamaStackExchange


Because it's almost Christmas and because Wings of The Warrior, the third book in The Huntress Chronicles is being released, I have decided to offer, for the first time, Wings of The Fallen and Wings of The Brave for free!
You can click on the links below!
Previous PostWings of The Warrior Release DateNext PostWings of The Warrior is Released!


In the work Muchismo, the photographer Cristina de Middel digs around in her studios and brings all of her images to light, exactly the way she has them stored, in colossal, gorgeous chaos, to show them in the exhibition of the same name to be held in June at the Teatro Fernán Gómez in Madrid. This is a sui generis display of her entire oeuvre, with neither a curator nor any apparent order, which seeks to question the art market and its rules.
At the same time, the artist is holding another exhibition of the Antipodes series in La Fábrica (Madrid), a series made up of pictures taken in New Zealand in which the artist strives to bring depth back to landscape photography by using mirrors and her own devices. Both works are captured in this publication, a book that had become an object of desire even before it materialised, as always happens with the works of one of the most fascinating photographers on today's scene.


text:
Godfather of British Jazz
This is the first biography of jazz pianist and composer Stan Tracey CBE (1926-2013). Drawing on personal diaries, Stan's many interviews over a career that spanned 70 years, and his own recollections of working with his father, Clark Tracey draws a picture of what made Stan Tracey a unique character in jazz music. In this very personal account, Stan's wit and wisdom come shining through in abundance.
The book begins with Stan's memories of war-torn London and his first experiences of hearing jazz. As a teenager, he joined ENSA and the RAF Gang Show. During the next three years he played at more venues than many musicians do in a lifetime, including a period in the Middle East. Once demobbed, Stan befriended pianist Eddie Thompson, vibraphonist and drummer Victor Feldman and clarinettist Vic Ash and began his professional career. He toured with Kenny Baker's band and the Kirchin Band before joining the Ted Heath Orchestra, after which he began recording under his own name. He was invited by Ronnie Scott to be the house pianist at Scott's new club, where his legendary status grew in the next six years. He accompanied giants of American jazz such as Stan Getz, Sonny Rollins, Roland Kirk, Dexter Gordon, Freddie Hubbard and many others. During this period he wrote and recorded the seminal album Under Milk Wood, which to this day remains his best-selling work. Stan left Ronnie's club during a period of drug addiction and in the 1970s found himself penniless. His wife Jackie employed her skill in the music business and began presenting concerts to keep Stan afloat, while he found new musical friends in the free/improvised idiom of the time, such as Mike Osborne and Keith Tippett. Commissions for suites emerged and Stan's writing skills found an outlet through the formation of his various groups that were to last for nearly thirty years. Stan's achievements and awards are numerous and in many cases unique. As well as an OBE and a CBE, he received several lifetime achievement awards and in his last year was the first recipient of the Ivor Novello Jazz Award.
The book includes a complete discography of all commercial recordings featuring Stan Tracey, compiled by Stephen Didymus.
You can obtain copies of this publication from the following web site (it is not available from our online store): https://www.equinoxpub.com/home/the-godfather-of-british-jazz/