import terminal import strutils import unicode import tables import json import os import math import sugar import sequtils import options import punycode import data/idna when defined(posix): import posix func ansiStyle*(str: string, style: Style): string = result &= ansiStyleCode(style) result &= str func ansiFgColor*(str: string, color: ForegroundColor): string = result &= ansiForegroundColorCode(color) result &= str func ansiReset*(str: string): string = result &= str result &= ansiResetCode func maxString*(str: string, max: int): string = if max < str.runeLen(): return str.runeSubstr(0, max - 2) & "$" return str func fitValueToSize*(str: string, size: int): string = if str.runeLen < size: return str & ' '.repeat(size - str.runeLen) return str.maxString(size) func isWhitespace*(c: char): bool {.inline.} = return c in {' ', '\n', '\r', '\t', '\f'} func onlyWhitespace*(s: string): bool = for c in s: if not c.isWhitespace(): return false return true const C0Controls = {chr(0x00)..chr(0x1F)} const Controls = (C0Controls + {chr(0x7F)}) const Ascii* = {chr(0x00)..chr(0x7F)} const Letters = {'A'..'Z', 'a'..'z'} const AllChars = {chr(0x00)..chr(0xFF)} const NonAscii = (AllChars - Ascii) const Digits = {'0'..'9'} const HexDigits = (Digits + {'a'..'f', 'A'..'F'}) func isControlChar*(c: char): bool = return c in Controls func isControlChar*(r: Rune): bool = case r of Rune(0x00)..Rune(0x1F): return true of Rune(0x7F): return true else: return false func isC0ControlOrSpace*(c: char): bool = return c in (Controls + {' '}) func genControlCharMap*(): string = for c in low(char)..high(char): if c == '?': result &= char(127) else: result &= char((int(c) and 0x1f)) const controlCharMap = genControlCharMap() func getControlChar*(c: char): char = return controlCharMap[int(c)] func genControlLetterMap*(): string = for c in low(char)..high(char): if c == char(127): result &= '?' else: result &= char((int(c) or 0x40)) const controlLetterMap = genControlLetterMap() func getControlLetter*(c: char): char = return controlLetterMap[int(c)] func findChar*(str: string, c: char, start: int = 0): int = var i = start while i < str.len: if str[i] == c: return i inc i return -1 func findChar*(str: string, c: Rune, start: int = 0): int = var i = start var n = i while i < str.runeLen(): var r: Rune fastRuneAt(str, n, r) if r == c: return i i = n return -1 func getLowerChars*(): string = result = "" for i in 0..255: if chr(i) in 'A'..'Z': result &= chr(i + 32) else: result &= chr(i) const lowerChars = getLowerChars() func tolower*(c: char): char = return lowerChars[int(c)] func toAsciiLower*(str: string): string = result = newString(str.len) for i in 0..str.high: result[i] = str[i].tolower() func genHexCharMap(): seq[int] = for i in 0..255: case chr(i) of '0'..'9': result &= i - ord('0') of 'a'..'f': result &= i - ord('a') + 10 of 'A'..'F': result &= i - ord('A') + 10 else: result &= -1 func genDecCharMap(): seq[int] = for i in 0..255: case chr(i) of '0'..'9': result &= i - ord('0') else: result &= -1 const hexCharMap = genHexCharMap() const decCharMap = genDecCharMap() func hexValue*(c: char): int = return hexCharMap[int(c)] func decValue*(c: char): int = return decCharMap[int(c)] func isAscii*(c: char): bool = return c in Ascii func isAscii*(r: Rune): bool = return int(r) < 128 func hexValue*(r: Rune): int = if int(r) < 256: return hexValue(char(r)) return -1 func decValue*(r: Rune): int = if int(r) < 256: return decValue(char(r)) return -1 const HexChars = "0123456789ABCDEF" func toHex*(c: char): string = result = newString(2) result[0] = HexChars[(uint8(c) shr 4)] result[1] = HexChars[(uint8(c) and 0xF)] func equalsIgnoreCase*(s1: seq[Rune], s2: string): bool = var i = 0 while i < min(s1.len, s2.len): if not s1[i].isAscii() or cast[char](s1[i]).tolower() != s2[i]: return false inc i return true func equalsIgnoreCase*(s1, s2: string): bool {.inline.} = return s1.cmpIgnoreCase(s2) == 0 func isAlphaAscii*(r: Rune): bool = return int(r) < 256 and isAlphaAscii(char(r)) func isDigitAscii*(r: Rune): bool = return int(r) < 256 and isDigit(char(r)) func substr*(s: seq[Rune], i, j: int): seq[Rune] = if s.len == 0: return @[] return s[min(high(s), i)..min(high(s), j - 1)] func substr*(s: seq[Rune], i: int): seq[Rune] = if i > high(s) or s.len == 0: return @[] return s[min(high(s), i)..high(s)] func skipBlanks*(buf: string, at: int): int = result = at while result < buf.len and buf[result].isWhitespace(): inc result func until*(s: string, c: char): string = var i = 0 while i < s.len: if s[i] == c: break result.add(s[i]) inc i func number_additive*(i: int, range: HSlice[int, int], symbols: openarray[(int, string)]): string = if i notin range: return $i var n = i var at = 0 while n > 0: if n >= symbols[at][0]: n -= symbols[at][0] result &= symbols[at][1] continue inc at return result const romanNumbers = [ (1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), (100, "C"), (90, "XC"), (50, "L"), (40, "XL"), (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I") ] const romanNumbers_lower = romanNumbers.map((x) => (x[0], x[1].tolower())) func romanNumber*(i: int): string = return number_additive(i, 1..3999, romanNumbers) func romanNumber_lower*(i: int): string = return number_additive(i, 1..3999, romanNumbers_lower) func japaneseNumber*(i: int): string = if i == 0: return "〇" var n = i if i < 0: result &= "マイナス" n *= -1 let o = n var ss: seq[string] var d = 0 while n > 0: let m = n mod 10 if m != 0: case d of 1: ss.add("十") of 2: ss.add("百") of 3: ss.add("千") of 4: ss.add("万") ss.add("一") of 5: ss.add("万") ss.add("十") of 6: ss.add("万") ss.add("百") of 7: ss.add("万") ss.add("千") ss.add("一") of 8: ss.add("億") ss.add("一") of 9: ss.add("億") ss.add("十") else: discard case m of 0: inc d n = n div 10 of 1: if o == n: ss.add("一") of 2: ss.add("二") of 3: ss.add("三") of 4: ss.add("四") of 5: ss.add("五") of 6: ss.add("六") of 7: ss.add("七") of 8: ss.add("八") of 9: ss.add("九") else: discard n -= m n = ss.len - 1 while n >= 0: result &= ss[n] dec n func parseInt32*(s: string): int = var sign = 1 var t = 1 var integer: int = 0 var e: int = 0 var i = 0 if i < s.len and s[i] == '-': sign = -1 inc i elif i < s.len and s[i] == '+': inc i while i < s.len and isDigit(s[i]): integer *= 10 integer += decValue(s[i]) inc i if i < s.len and (s[i] == 'e' or s[i] == 'E'): inc i if i < s.len and s[i] == '-': t = -1 inc i elif i < s.len and s[i] == '+': inc i while i < s.len and isDigit(s[i]): e *= 10 e += decValue(s[i]) inc i return sign * integer * 10 ^ (t * e) func parseInt64*(s: string): int64 = var sign = 1 var t = 1 var integer: int64 = 0 var e: int64 = 0 var i = 0 if i < s.len and s[i] == '-': sign = -1 inc i elif i < s.len and s[i] == '+': inc i while i < s.len and isDigit(s[i]): integer *= 10 integer += decValue(s[i]) inc i if i < s.len and (s[i] == 'e' or s[i] == 'E'): inc i if i < s.len and s[i] == '-': t = -1 inc i elif i < s.len and s[i] == '+': inc i while i < s.len and isDigit(s[i]): e *= 10 e += decValue(s[i]) inc i return sign * integer * 10 ^ (t * e) func parseFloat64*(s: string): float64 = var sign = 1 var t = 1 var d = 0 var integer: float64 = 0 var f: float64 = 0 var e: float64 = 0 var i = 0 if i < s.len and s[i] == '-': sign = -1 inc i elif i < s.len and s[i] == '+': inc i while i < s.len and isDigit(s[i]): integer *= 10 integer += float64(decValue(s[i])) inc i if i < s.len and s[i] == '.': inc i while i < s.len and isDigit(s[i]): f *= 10 f += float64(decValue(s[i])) inc i inc d if i < s.len and (s[i] == 'e' or s[i] == 'E'): inc i if i < s.len and s[i] == '-': t = -1 inc i elif i < s.len and s[i] == '+': inc i while i < s.len and isDigit(s[i]): e *= 10 e += float64(decValue(s[i])) inc i return float64(sign) * (integer + f * pow(10, float64(-d))) * pow(10, (float64(t) * e)) const ControlPercentEncodeSet* = (Controls + NonAscii) const FragmentPercentEncodeSet* = (Controls + NonAscii) const QueryPercentEncodeSet* = (ControlPercentEncodeSet + {' ', '"', '#', '<', '>'}) const SpecialQueryPercentEncodeSet* = (QueryPercentEncodeSet + {'\''}) const PathPercentEncodeSet* = (QueryPercentEncodeSet + {'?', '`', '{', '}'}) const UserInfoPercentEncodeSet* = (PathPercentEncodeSet + {'/', ':', ';', '=', '@', '['..'^', '|'}) proc percentEncode*(append: var string, c: char, set: set[char]) {.inline.} = if c notin set: append &= c else: append &= '%' append &= c.toHex() proc percentEncode*(append: var string, s: string, set: set[char]) {.inline.} = for c in s: append.percentEncode(c, set) func percentEncode*(c: char, set: set[char]): string {.inline.} = result.percentEncode(c, set) func percentDecode*(input: string): string = var i = 0 while i < input.len: let c = input[i] if c != '%' or i + 2 >= input.len: result &= c else: let h1 = input[i + 1].hexValue let h2 = input[i + 2].hexValue if h1 == -1 or h2 == -1: result &= c else: result &= char((h1 shl 4) or h2) i += 2 inc i #basically std join but with char func join*(ss: openarray[string], sep: char): string = if ss.len == 0: return "" var n = ss.high - 1 for i in 0..high(ss): n += ss[i].len result = newStringOfCap(n) result &= ss[0] for i in 1..high(ss): result &= sep result &= ss[i] func clearControls*(s: string): string = for c in s: if c notin Controls: result &= c func processIdna(str: string, checkhyphens, checkbidi, checkjoiners, transitionalprocessing: bool): Option[string] = var mapped = "" var i = 0 while i < str.len: var r: Rune fastRuneAt(str, i, r) let status = getIdnaTableStatus(r) case status of IDNA_DISALLOWED: return none(string) #error of IDNA_IGNORED: discard of IDNA_MAPPED: mapped &= getIdnaMapped(r) of IDNA_DEVIATION: if transitionalprocessing: mapped &= getDeviationMapped(r) else: mapped &= r of IDNA_VALID: mapped &= r #TODO normalize var labels: seq[string] for label in str.split('.'): var s = label if label.startsWith("xn--"): try: s = punycode.decode(label) except PunyError: return none(string) #error #TODO check normalization if checkhyphens: if s.len >= 4 and s[2] == '-' and s[3] == '-': return none(string) #error if s.len > 0 and s[0] == '-' and s[^1] == '-': return none(string) #error var i = 0 while i < s.len: if s[i] == '.': return none(string) #error var r: Rune fastRuneAt(str, i, r) #TODO check general category mark let status = getIdnaTableStatus(r) case status of IDNA_DISALLOWED, IDNA_IGNORED, IDNA_MAPPED: return none(string) #error of IDNA_DEVIATION: if transitionalprocessing: return none(string) #error of IDNA_VALID: discard #TODO check joiners #TODO check bidi labels.add(s) return labels.join('.').some func unicodeToAscii*(s: string, checkhyphens, checkbidi, checkjoiners, transitionalprocessing, verifydnslength: bool): Option[string] = let processed = s.processIdna(checkhyphens, checkbidi, checkjoiners, transitionalprocessing) if processed.isnone: return none(string) #error var labels: seq[string] for label in processed.get.split('.'): var needsconversion = false for c in label: if c notin Ascii: needsconversion = true break if needsconversion: try: let converted = "xn--" & punycode.encode(label) #TODO verify dns length labels.add(converted) exc
<HTML>
<HEAD>
<TITLE>Stop Saying ``Computer Literacy''!</TITLE>
</HEAD>
<BODY>
<H1>Stop Saying ``Computer Literacy''!</H1>
<CITE>Brian Harvey<BR>University of California, Berkeley</CITE>
<P>[A version of this paper was published in <EM>Classroom Computer
News</EM> in 1983.]
<P>As computers become more widely used in schools, educators have invented
many different ways to use them. The different uses for computers
are based on quite diverse models of what the purposes of computer
education should be. One very common approach is based on the notion
of ``computer literacy'': the idea that there is some basic familiarity
with computers which <EM>all</EM> students need in order to compete in
the job market, or to be informed citizens. The purpose of this paper
is to question whether that notion is valid.
<H2>The Importance of Metaphor</H2>
<P>Several educators have questioned the specific details of particular
``literacy'' plans, while accepting the overall concept. ``Computer
literacy doesn't mean X,'' they say, ``it means Y.'' For example,
Arthur Luehrmann says, ``[C]omputer literacy must also mean the ability
to <EM>do</EM> computing, and not merely to recognize, identify, or be
aware of alleged facts about computing.'' (Luehrmann, 1981) His
argument is that a computer curriculum should give students actual
programming experience, not just reading about computers in a book.
But Luehrmann accepts the concept of computer literacy itself, the
idea that there is <EM>something</EM> which every student must learn.
He questions only the details of just what this something is.
<P>What I would like to do is call into question the claim that there
is anything about computers which belongs in the school experience
of <EM>every</EM> student. I agree with Luehrmann that programming can
be a valuable experience. But the word ``literacy'' means more than
that; it means that everyone must have the experience in order to
be able to function at all in society.
<P>Many people, hearing me make this argument, have complained that it
is foolish to argue about a word. ``Call it something else,
then, and let's get on with deciding what it should be.'' This complaint
misses the point, and indeed could be said to prove the point. People
who have become accustomed to the ``literacy'' idea find it very difficult
even to entertain the question of whether there is any universally
required computer experience.
<P>The trouble is that the word ``literacy'' is a magic word, which conjures
up a very strong metaphor. Literacy in its original sense, knowing
how to read, really <EM>is</EM> universally required in our society.
Any educator who suggested eliminating reading from the curriculum
would be laughed at, if not tarred and feathered. Merely to say the
phrase ``computer literacy'' definitively answers a question which
has not explicitly been asked. It's like the classic ``When
did you stop beating your wife,'' but harder to recognize because
it is so widely used.
<P>One practical result of the literacy metaphor is that many decisions about
computer education have been made in a kind of panic. Parents call up the
school committee to ask why their children are not being trained for the
vital computer job skill. These parents may not know just what that skill
is, and neither does the school committee. But they do know that the
private school down the road has computers.
<H2>What Everyone Needs to Know</H2>
<P>It's quite true that more and more jobs involve the use of computers.
That's different from saying that these jobs involve computer
<EM>expertise</EM>. Let's look at some examples.
<P>A good example of a computer-using job
is that of selling hamburgers at McDonald's.
That machine behind the counter which looks like a cash register is
actually a computer terminal. When you order a Quarter-pounder with
cheese, instead of ringing up whatever the price is, the counter person
pushes a button which says ``Quarter-pounder with cheese.''
The computer displays the price, but it also keeps track of how many
of this item are sitting under the heat lamps. If they're running
short, the computer tells the cooks in the back to make more. The
same computer can tell the manager to buy more hamburger buns at the
right time. It's a pretty sophisticated system, and helps make McDonald's
a low-overhead operation.
<P>Now, what does the person behind the McDonald's counter need to know
about computers? He only needs to know that when you ask for a
Quarter-pounder with cheese, he should push the button which says
``Quarter-pounder with cheese.'' That's it. Nothing about input
unit, output unit, processor, and memory; nothing about programming
either.
<P>Perhaps a more common example is that of computer word processing.
The word processor involves a much more intimate interaction with
the computer than selling hamburgers. Still, the manufacturers of
word processing systems take pains to <EM>hide</EM> the computer, to
make the way you operate the machine as much as possible like operating
an ordinary typewriter. What skills does a word processing operator
need? For the most part, exactly the same skills a secretary needed
before word processing: good spelling and punctuation, touch typing,
being able to read the boss's handwriting. What the computer adds
is mostly a matter of pushing the ``paragraph'' button instead of
the carriage return and the tab.
<P>There are more specifically computer-related skills, of course, like
threading the fanfold paper into the printer. But that's the sort
of thing which is done differently for each specific model, and which
is part of a very specific job training program. It isn't what you'd
teach in a ``computer literacy'' course for everyone.
<P>Perhaps the point really is that there are too many <EM>different</EM>
computer-related skills to teach all of them to every student. Using
a spreadsheet program, for example, is very different from using a
word processor. Using a microprocessor-controlled automobile engine
tester is very different from either. Neither ``this is the return
key'' nor actual programming will help much with any of those job
activities.