“Kickin' it Old-school“ –or–
“Every True Geek should use his own Editor”
This is an implementation of the CP/M-80 editor
ED
. All features of ED
(with one exception, K
is a bit different)
are supported. I started my career with punched cards, and then
when microcomputers were introduced, CP/M, and still prefer its
editor. Actually, I used a line editor called ADE
(Assembler/Editor/Debugger for the 6502) before I used
ED
, but ADE
didn't even have string
search, and also a system called Software Package One
(for the 8080). Both ADE
and SP/1
were
tape based, which was somewhat better than punched cards. I also
used WordStar 3
on CP/M-80 (in non-document mode) for
entering programs. The WordStar interface was carried forward by
Borland, but this editor (WordStar) was still not my personal
preference.
I actually used TECO
for a while on a PDP/10 before
using CP/M; I just never got good at it. Just like CP/M-80
ED
, this editor can be considered in the
TECO
family. Actually, CP/M-80 ED
is a cross between TECO
and TSO EDIT
(IBM 360).
This implementation is rather crude, but it is only for my
personal use. I truly do not expect anyone else to ever use
this code. Goals are to keep the size of the editor down, and
increase portability. The editor has pretty much no features
that “modern” editors have; indeed it can be considered
almost user hostile! Help is implemented, via the ?
command. This implementation uses the simplest possible format
for the edit buffer – just an array of characters. This
makes insert and delete character very expensive operations.
However, systems are so fast these days that this simple
organization is actually sufficient.
If you are not comfortable with the CP/M-80 ED
commands, you may (will) absolutely hate this editor. If you are
old-school enough to have used TECO
, you may also
hate this editor – it will be too restrictive. Of course,
it really isn't user hostile, because the only user is me, and I
am happy with it. I was warped by CP/M-80 ED
. The
real reason this document exists is to provide amusement to my
kids after I am dead!
CPMED
is an improvement on ED
. Not as
many spurious newlines are produced; it has many more features,
and is comparable on a size basis (10K for ED
on an 8-bit system, 40K for CPMED
on a 64 bit
system). CPMED
has over twice the commands
ED
does, including a full RPN calculator (with
decimal, octal and hex input and output), and full looping,
nesting and conditional command execution. Four help pages are
included, giving an overview of CPMED
commands
and operation. This is important, as there are over 50 commands
available in CPMED
.
VEDIT was a commercial implementation of the same idea –
a visual interface to ED
. VEDIT's macro language
was originally a lot more like TECO
, and is now
C-like. Arguably, a lot more powerful than CPMED
,
but, it didn't come with source, and I didn't write it.
The first 8086 implementation of CPMED
was on an
IBM PC, running PC-DOS in 1984. I wrote it because I preferred
the command syntax and features of the CP/M ED
editor to Microsofts EDLIN
. They were similar, but
ED
was line and character oriented while
EDLIN
was only line oriented, and I was familiar
with ED
. A conversion was done in 1986 moving
the editor to XENIX, and then in 1996 moving
the editor to Linux and Solaris. Again, I was comfortable with
ED
and not with vi
or
emacs
. The source code for CPMED
is
organized such that it can be edited even on an uppercase only
terminal (I used such limited terminals up to 1989).
I still actively use CPMED
. The current VT100
based scope implementation was done in 1996, when the editor was
first moved to SUN Solaris. A limited scope implementation
was done on the IBM PC, utilizing direct memory-mapped
display, but this had to be completely redone for a VT100
terminal. COBOL marking on the ruler line was added in 2009,
for some maintainance Micro Focus COBOL work. This is the only
software that I have used for this long (30 years, so far).
By the time this editor was converted to use scope mode for a VT100, minimum processor speeds were already at 200Mhz (to 1GHz). As a result, the scope mode was left inefficient. I have never gotten around to optimizing this (beyond simple one line updates). Eventually, the scope mode may be re-written to use screen buffer deltas.
As a side note, the core of this editor was initially coded in C!
The Whitesmiths compiler was used to produce a simple screen
editor on a Z80, under CP/M for customers of a disk conversion
system. The Z80 version was simple, relying on arrow keys
and other special keyboard keys, with a very limited set of
features. The edit buffer was originally represented as a list
of fragments. Fragments were of the same size (128 bytes),
to avoid allocations from fragmenting memory. That editor
would also move fragments to disk, to increase the available
memory. Disk address for virtual memory for that editor was 16
bits, allowing 8MB maximum file size. This meant a practical
maximum of 256,000 bytes per file. (which was also the limit
for SSSD CP/M floppies – 256,256 bytes, and CP/M-80
imposed a limit of 8MB on hard disks). Since we no longer have
that memory restriction, and computers are so much faster,
CPMED
uses a simple character buffer approach
(but does impose an 8 megabyte limit on edit buffer size). I
normally set a 2 megabyte edit buffer size. CPMED
has four edit buffers, selected with the .Z command. Buffer 1.Z
is the "primary" buffer. 2.Z is for macro definitions, accesible
with the .C (call) command (also .R - return). Buffers 3 and 4
are available as scratch buffers. ED
only supported
a single edit buffer.
However, even today CPMED
is able to run on
upper-case only printing terminals! (even though I haven't
needed that feature in 30 years). In the incarnation on
XENIX, a very limited (11 line) preview could
be used. Scrolling regions were not needed – instead 5
lines around the current point were displayed, with an optional
clear terminal. This is the major reason that scope mode is
still inefficient today.
Some features have been added to support my programming style: brace matching for LISP/SCHEME, UNDO, rulers for the languages I use, a vertical bar for alignment, auto indent, re-indent, and more extensive macros, including conditionals and looping. As well, UTF-8 characters can be entered and displayed if using a terminal emulator that is suitably configured. Again, the feature set is exactly what I use, because this editor has an audience of one.
CPMED
supports printing terminals, with as little
as the capability of a TTY33. Scope mode (full screen) is
supported, and assumes the terminal respect VT100/VT220 escape
sequences. It runs on Linux Console. UTF-8 is also (fairly
crudely) supported. Scrolling regions are a requirement for
scope mode.
These terminals do not support backspace. Erase a
character echoes the erased character .3
command
allows lowercase to be viewed, and U
allows forcing
everything to uppercase. ^R
on entry allows
retyping of corrected entry. If .3
mode is enabled,
lowercase ‘a’ is displayed as [A]
. This allows
limited lowercase to be edited on such a device (specifically,
cpmed.c
itself can be edited).
Backspace may work correctly (note that BS/RUBOUT are reversed
in scope mode – for convenience). KEYRUB and KEYBS can
be assigned in =
commands. 0P
,
P
and -P
are effective at
displaying files. If the “normal” backspace key deletes
via “rubout”:
ABC[backspace] produces ABCC
then the input can be “cleaned up” with ^R
ABCC^R ABC
The “rubout” code (127, DEL) can be assigned to backspace:
=127>[keybs]
And, now the “normal” backspace should function as
expected. Note that .S
(fullscreen) does this:
=127>[KEYBS] =8>[KEYRUB]
because it assumes a VT100 key mapping.
These terminals allow the use of scope mode
(.S
). Full screen editing is possible. Assume
7 bit ASCII character set. .E
provides a
SEEALL mode where all characters
are visible. 2.S
mode is provided for slow links,
or line editing can be utilized.
Full screen editing. .F
enables UTF-8 editing
(and sets 8 bit .D
as well). This displays UTF-8
symbols (assuming the device can), and utilizes VT100 escape
sequences to control the terminal. The C
and
D
commands are UTF-8 aware. Be aware that up to 6
bytes may be erased with a D
command in this mode.
CPMED
is probably also full of bugs, although
it has been run with several different compilers, and in
32 and 64 bit modes, big and little endian (and on multiple
OSs). The distribution contains binary (compiled) versions for
| Platform | Bits | OS | Endian |
|---|---|---|---|
| PA-RISC2.0 | 32 bit | HP-UX | Big Endian |
| Sparc 32 | 32 bit | Solaris | Big Endian | x86_64 | 64 bit | Linux | Little Endian |
CPMED
“buginess” doesn't matter, because I am
the only user, and it works for me.
The purpose of a text editor (especially a programming editor)
is to enter and revise ASCII (and, these days, UTF-8) text,
conveniently and precisely. Text must be entered quickly in
the format required by the language processor, and revisions
should be fast and accurate. Any on-screen representation
must facilitate these goals, without interfering with the
creative process. CP/M-80 ED
met most of these
requirements, but did not provide a full screen view of
the code.
The full screen view must represent the printed program text closely, and must provide the detail required to edit and format the program text.
A text editor will be used in one of three “modes”. First is to enter text, where the text is known, or being composed. This requires positioning to the entry location (“Find”, line number), a ruler to assist in horizontal formatting (possibly a margin bell or bar(s), and tabulation). The second mode is revising text. Again, location to the position, followed by entry, deletion or replacement. The third mode is simply reading. A clean and uncluttered display is best, perhaps assisted by line numbering or change notification devices. Editing automation is important.
To these ends, CPMED
supports highlighting a
column (for FORTRAN, COBOL or ASSEMBLER). and the ability
to view “invisible” characters such as spaces, tabs and
other control characters. It edits text and ONLY text. Any
formatting function is relegated to external commands. There
is one integrated formatting function – auto indentation
on a new line, and the ability to re-indent lines.
CPMED
supports a margin bell. 72.B
will sound the bell if text is entered past column 72. This
applies only to the I
command, and not the
command line.
CPMED
supports variable tabulation.
-.H
clears all set tabs. n.H
(7.H
for FORTRAN, as an example) sets (or if
already set, clears), a horizontal tab. When ^W
is entered during the I
command, spaces are
inserted to move to the next tabulation column. Up to 20
tabulation columns can be set. The naked .H
command will display the tabulations that are set (all 20, with
0 indicating available tabulations).
When a file is read, flags are set according to the files
extension (.FTN
would be FORTRAN). Also, as
lines are read from the file, if a “ce” line is read
(space “CE:” followed by commands), the commands are
submitted, and this can set the file type. Note that ‘;’
character is replaced by ^Z
in the command,
and that first ‘;’ terminates the command, and submits it.
For example
ce: .f.mhtml;
sets UTF-8 and the edit mode to text.
The ‘;’ handling is to make it easy to enter the
.M
command without needing to escape a
^Z
. Using the “ce” lines for other tasks
may be more difficult, but still possible.
/
repeats the last find or substitute
command. ^A
repeats the last command. As well,
the *
(shelf) command will copy characters to
the “shelf” which can be retrieved into the command line
using ^F
. For example, if the point is at the
beginning of a C function definition, -*(^Z
would store the function name to the shelf. Subsequently,
F^F
would build the F
command to
find that function name. 0*string
will
store string to the shelf, 10*
will store
the next 10 characters from the edit buffer to the shelf,
and -*c^Z
will store all characters up
to c from the edit buffer. Note that the argument to
-*
is a single character, but it must still be
terminated by ^D
or ^Z
.
Macros are supported by the M
command,
( )
looping and conditionals.
 There
are very few features, and very few extraneous display
elements. But, CPMED
is driven by my needs
and philosophy, and does not reflect any GUI design,
discoverability or any other features and designs. This is
my editor; not your editor, and, as long as
the user base remains 1, will stay that way.
In scope mode, there is a region for the file being edited,
a separator line that changes according to the language
(for editing fixed format FORTRAN and COBOL, which I still
do), and a scrollable command entry area. Editors such as
vi
do not work well for classic FORTRAN, because
of the requirement for specific columns. The user would need
to be very careful on entering new lines, or enable a column
counter (if using, say, vim). Using CPMED
,
the command 7.G
would highlight the start of
statement column. 72.G
highlights the end
of statement column, allowing easy verification of the
input program. 72.B
would ring a bell on
exceeding the statement limit. Setting a tab at column 7
using 7.H
allows ^W
to tab to the
statement part. U
automatically uppercases
imput. This makes for easy FORTRAN entry.
Many extensions to ED
are provided by
CPMED
. They include ability to suppress
“Y/N” prompts, 8 bit (UTF-8) character support, settable
tab expansion and auto indentation, scope mode (full screen
support), LF and CR/LF file handling, rubout cancellations,
brace matching, simple programming, indent/outdent, marks,
binary editing, shell, piping, repeat commands, multiple
programming languages, UNDO, vertical marking and sourcing
of input are now provided. CPMED
tries to not
issue as many line-feeds to reduce output.
CPMED
has the ability to edit binary
files. Files may contain any 8-bit character (0 to 255). The
n.I
command inserts the character with
value n (eg. 0.I
will enter a NUL). These
characters will be displayed as [hh]
in -.D
(non-eightbit) mode where hh is
a two hexadecimal octet, and will be passed through to the
terminal in .D
(eightbit). To enter the value
in hex, the =
command can be used, along with
the ^
command prefix:
*= HEF^Z ^.I
will enter character EF hex
into
buffer. 0.T
will display tabs as ^I
instead of expanding them, which is helpful in editing
binary files. Newlines will still cause line breaks, but
no other characters will be interpreted (controls display
as ^C
; [00]
is null, and 127-255
are displayed as [7F]-[FF]
).
In .D
(eightbit) mode, all output characters are
passed through a UTF-8 filter. Column locations are based
on the output of that filter, and correctly accomodate
UTF-8 sequences. It is presumed that the terminal will
interpret UTF-8 sequences and display the correct character.
External filters invoked with .!
may not interpret
UTF-8 correctly.
A scope mode that requires a VT100 (or equivalent) with
scrolling regions is provided. Scope mode is useful in that it
provides visual context for edit commands. A ruler is displayed
in scope mode, with FORTRAN, COBOL and other programming
language columns marked, a marker every 10 characters, and
columns 64 and 72 shown. When in scope mode, 18 lines of the
edit buffer are shown, followed by a dividing ruler line, with
a 5 line scrolling region at the bottom for commands. Other
screen sizes (than 80x24) are supported. The command area
is normally 5 lines. If the width is 132 or greater, column
132 is marked on the ruler. After changing screen size, use
.S,
or ^V
to refresh the editors
notion of the screen size.
In scope mode, FORTRAN, COBOL, LISP, and SNOBOL bolds
comments. ‘#’ or ‘;’ at the beginning of a line bolds
the line. ‘*’ at the beginning in SNOBOL bolds the line,
and ‘C’, ‘c’, ‘*’ or ‘!’ in FORTRAN bolds. Only
single line comments are bolded – CPMED
makes no attempt to actually interpret the syntax of the
language. This is simply an assist to reading code.
Note that ‘#’ line bolding means AWK, RATFOR, SHELL, and other languages will be comment highlighted. In C mode, ‘#’ and ‘;’ lines will not be bolded.
A vertical bar can be enabled. The bar extends down the scope
display to the ruler line, allowing for column alignment.
The G
and .G
commands control the
vertical bar display. The bar is not saved in the buffer,
but is only a display device.
Since scope mode is so useful, I use it most of the
time. Indeed, some commands (indent/outdent and brace match)
are particularly useful in scope mode, and not as useful
in scrolling terminal mode. The scope mode may be improved
by double-buffering the screen and using screen deltas to
update the display. This will allow scroll up and down to be
exploited (of use with slow communications lines). I haven't
yet implemented this (the entire screen is refreshed each time,
with single-line optimizations). However, 2.S
enters a scope update mode that is limited to explicit
updates. This and limiting the number of scope lines is useful
when editing files over very slow communications links.
When in scope mode, -I
and cursor
motions on the same line are optimized and only cause
a single line redraw. Other commands will cause a full
refresh. 2.S
mode (hold mode) is still more
efficient. In scope mode, SEEALL
is available (.E
). This shows spaces and line
ends as characters (.
and <
, both
dimmed). Tabs will be white space, (unless tab expansion is
disabled, in which case a tab is displayed as ^I
).
A brace match feature is implemented. ,
matches
([{<>}])
and moves the point to the matching
brace. I implemented this to assist in SCHEME programming.
^A
repeats the last typed command (“again”)
and /
repeats the last search command
(F
, S
, N
, or
J
).
The J
(“juxtapose”) command can be very
useful. Given:
MYVAR = EXPR
the command JMY^ZNEW^Z ^Z
searches for “MY”,
replaces with “NEW”, and then deletes until a space,
resulting in:
NEW = EXPR
The K
command kills lines. 0K
deletes until the beginning of the line, but does not
remove the line-end marker. K
deletes to the
end of the line, including the line-end marker. However,
the command J^Z^Z^P^J^Z
will delete from the
current point to the line-end, but not include the line
end! This is J
(“juxtapose”), no search,
no replace, and delete until the line-end (^P
quotes, and ^J
is line-end). By default,
^L
in search strings accomplishes the same
thing (see .L
), so this can be expressed as
J^Z^Z^L^Z
as well.
The command 1::3T
is interpreted as
1:
which is count 1 followed by :
as a command, which positions the point to line 1. The
second command is :3T
. :3
computes
the repetition to execute the command to line three, and
T
types lines. So 1::3T
types lines
1 to 3.
The # count is not 65535 – it is the greater of 65535
and BSIZE (which is 512K by default). This is the maximum
number of characters in the edit buffer, so #C
will be -B
. However, the line numbering is
1 to 99999 (5 digit). This should be just fine for most
source files. Any line numbers greater than 5 digits will
be displayed as #####. If a line number is greater than
5 digits, it can be entered and used. To display it, use
=[LN]P
. Note that -# is supported,
so -#C
is equivalent to B
(and,
in reality, B
is executed as -#C
and -B
is #C
. This keeps line
numbering correct).
The startup command is
ce infile [outfile] [-e commands]
If only a single file is given, this will be used as both
the input and output files. The original input file will
become the backup file (.bak extension). If two names are
given, input will be from the first file, and output to the
second. No backup file will be generated. As well, commands to
be executed (for example #a100:
to go to line 100)
can follow -e
. The 4V
command will
display all filenames currently assigned (this takes 3 lines
of output). If only a single filename is given, the output
file will be /tmp/fileCxmnCU
(for example). A
unique /tmp
filename is generated. On completing
the edit (E
), the output file will be copied to
the input file (if no outfile was given).
Each -e "command" on the command line has a ^Z appended.
Normally, ^Z cannot be entered on the shell
command line, and this would prevent S commands from being
entered on the command line, however:
ED file -e '#a' -e '#sFROM' -e 'TO' -e '.ye'
will work. A ^Z doesn't do anything as a command. All of the -e commands are concatenated, separated by ^Z. The .y disables any Y/N prompting. So, this command edits the file, replacing all occurences of FROM with TO.
If two filenames are given (in and out), the H
command will flip them around. This allows editing from the
beginning again.
The edit buffer size is controlled via REGION. Default is 512K; if a number less than 2048 is given, the size in multiplied by 1024. The maximum size is 8 megabytes. The default of 512K corresponds to 6553 card images (of 80 characters).
REGION=64 ce myfile
Suffixes of “K” and “M” can be used:
REGION=2M
for a 2 megabyte edit buffer. Maximum edit buffer is 8
megabytes. This does not limit the size of file that can be
edited. The A
and W
commands can
be used to page through the file if needed. Practically,
though, 8 MB should be sufficient for any source editing
(the largest file I routinely edit is a FORTRAN program 1
million bytes in size, or over 32,000 lines).
The ..
command “sources” files. Commands are
read from the file. First, the command file is opened in the
current directory. If not found, directory specified by CELIB
in the environment is tried. Any commands on the command line
after ..
are ignored.
CELIB=/usr/share/celib REGION=512 ce file -e "#a.s"
When the editor is started, file .cpmedrc
is
sourced from the current directory first, or from CELIB,
if it exists in either location. The commands on the command
line (if any) are then executed. Putting #a.s
into a local .cpmedrc
can be used, for example,
to convert the editor to full screen.
The Y
command is an UNDO. All changes made can
be reverted using the O
command (original). As
text is deleted and inserted (or substituted), the changes
are recorded in an UNDO buffer. On insert (I
commands), a mark is recorded on each newline. A single
Y
command will undo to the last mark. Multiple
marks, character insertions and deletions (up to the UNDO
limit) are recorded. W
and A
commands clear the UNDO buffer. For example 3K
will remove 3 lines. Y
will undo each of
the K
operations. A mark is set on entry to
the kill. On deletion of a newline, another mark set set.
The first undo will undo the final newline delete. The next
will restore back to the previous newline. This will appear as
if 2 Y
commands are needed to restore the final
line, and one for each line thereafter. The UNDO environment
variable controls the number of UNDO records retained. The
default is 1024.
UNDO=2000 ce ...
Each UNDO record is one character deleted or inserted,
or an operation mark. This means that at an (average) of
40 characters per line, the last 25 lines of editing can be
“undone”, assuming 1024 UNDO records. The Y
command does not repect the numeric count. This is because
the UNDO cannot itself be “undone”.
CPMED supports an alternate edit buffer. This will be used
to hold information needed by macros but at present is not
used. The default size is 16K, but this can be adjusted
using the REGION2 environment variable. Like REGION, K and M
suffixes are supported. The .Z
command selects
the edit region. .Z
selects the primary, and
2.Z
selects the alternate. The E
,
A
, W
, Q
and other
file commands do not function when the alternate region is
selected. Only R
and X
can transfer
from disk.
This implementation supports auto-indent. If enabled each line
entered in input mode is automatically indented to the same
level as the previous line. This is accomplished by inserting
tabs and spaces. ^T
and ^G
can be
used to indent or outdent. To automate this, the %
command is bound to indent/outdent. To indent the next 10
lines by 2 indents (4 characters per indent in C mode):
10M2%L
An editing mode can be set. Currently, nine are
supported: TEXT, FORTRAN, COBOL, PASCAL, SNOBOL4, LISP, C,
SHELL and ASSEMBLER. As well, sub-modes are available: YACC,
LEX, RATFOR, SCHEME, LITERATE, DC, HTML, SABLE, PERL, SED,
TCL, SQL, BASIC, AWK, BC, APL, MAKE and REXX. .M^Z
sets TEXT, .MFORTRAN^Z
sets FORTRAN.
Initially, the mode is set from the file extension (for
example: .FTN
enables FORTRAN). On A
(append) each line is scanned for (space)ce: commands; where
commands will be submitted. I insert these CE lines into my
source templates.
Note that the mode selects tabulation, auto indent, the ruler
line, and has an effect on comment bolding. Syntax highlighting
and automatic expansion are not done. For example, when FORTRAN
is selected, a tabulation is set a column 7. ^W
will insert spaces to that tabulation point. As well, the
margin bell is set to 72.
After a series of edits, the H
(head) command can
be used to commit the changes and rewind the input file. If
an edit is done in error, the O
command can
be used to restore the original input file and rewind (or
Q
can be used to quit the edit). After rewinding,
the source file must be read into the edit buffer again using
the A
command (0A
, #A
).
.T .Y .8 ? .D .S / , ! .! .A .I @ .@ # <tab>text -I G .G .. .M .3 .L .E .F .H .X ( ) $ = _ ^ & Y 2V 3V 4V % .Z .V *
^C |
Abend if first character on line |
^Z, ^D |
End of string, end of insert |
^E |
Start new physical line |
^M, CR |
Execute command, if empty command, then advance and type |
^R |
Echo #, retype line, tty |
^U |
Abandon line, tty. Issues newline, and indents to start. |
^X |
Abandon line, crt. Backspaces to beginning. |
RUBOUT |
Erase character, tty. Echoes character erased. |
BACKSP |
Erase character, crt |
^L |
Line end in S, F, J (see .L command) |
^A |
Again, repeat last command line |
^P |
Quote next character |
^T |
Increase indent |
^G |
Decrease indent |
^B |
Brace match |
^F |
Insert shelf |
^W |
Space to next tabulation |
Note that ^T
, ^G
, and autoindent only
work in -I
insert in scope mode. Be careful when
using immediate commands. Immediate commands “cancel” the
command line entry, and replace it with the immediate command.
Note that RUBOUT and BACKSP are reversed if scope mode is enabled (we know we are using a VT100 terminal – or terminal emulator).
The format of numbers is a bit more sophisticated than CP/M-80
ED
. Number format is:
10T |
Type 10 lines |
-5C |
Move back 5 characters |
:20T |
Type through line 20 |
10::20T |
Type lines 10 through 20 |
@3T |
Type through mark 3 |
2@@3T |
Type from mark 2 through mark 3 |
#T |
Type all from current |
10::20-1T |
Type lines 10 through 19 |
10::20+2T |
Type lines 10 through 22 |
^T |
Transfer expression result to count Note that ^ here does not represent control, but is the circumflex character itself |
& |
Read the next number from the index file (see .N) and use that for the argument. Normally, the number is relative number of lines from current line (may be in character units, or something else entirely, for = expressions). Fails if non-number in the file, or end of file. |
Trailing + or - n is really only useful when using @n line marks.
NO EDIT BUFFER |
Cannot allocate edit buffer |
NEW FILE |
File is new |
NO FILE |
No file on command line |
BREAK ">" AT c |
Buffer full |
BREAK "?" AT c |
Command error |
BREAK "O" AT c |
No transfer file |
BREAK "#" AT c |
Repetition exhausted |
BREAK "B" AT c |
Rubout canceled macro, or search |
DISK ERROR |
Problem reading or writing to disk |
PROBLEM WRITING BACKUP |
Can't write backup file |
CANNOT COPY $ TO TMP |
A problem in .! copying the transfer file to /TMP/$$. The region is already erased from the edit buffer, maybe 'r' can read it back. |
PROBLEM WRITING FILE - SEE |
Problem writing file (may be write protected). Edit changes are in the file named, and this can be copied. |
The character c is the command character that caused the
error. For example, BREAK "?" AT ~
indicates a bad
command. If you entered Fxyzzy
, a BREAK "#"
AT F
indicates that the string cannot be found from the
current point to the end of the edit buffer. If an error occurs
in a ‘.’ command, the command character will be the second
character in the sequence (T
for .T
).
CPMED
has over 50 commands. It is a context
editor that has an edit buffer. Within the buffer there is
a “point” (CP) at which inserts and deletions occur. The
buffer is a fixed size; the file to be edited may be larger
than the buffer, and the file can be paged through the buffer.
Each command is a single character, or a dot (.) followed by a character, and may have (1 to 3) string arguments following. The command letter can be preceded by a count. The count is an optional + or -, followed by digits or a # mark. The # means 512K (edit buffer size). A : may follow the number, which computes the difference (in lines) between the current point and the entered line number. Note that the : character serves two purposes – as a command it goes to a line, and as an numeric it computes the line delta. An @ computes the difference in lines between the current point and a line mark.
The complete set of CP/M-80 ED
commands is
supported, along with many added commands.
A | Append lines from input file | ||
nA |
Append n lines | ||
0A |
Append until buffer 1/2 full | ||
#A |
Append all lines | ||
-nA |
Append n pages (page is text terminated by form-feed) | ||
.A | Autoindent | ||
.A |
Enable autoindent | ||
-.A |
Disable autoindent | ||
n.A |
Set indent amount | ||
B | Move to Begin/End | ||
nB |
Move to beginning | ||
n-B |
Move to end. Equivalent to #C or -#C | ||
.B | Margin Bell. Alarm on I command after exceeding column. | ||
n72.B |
Alarm on 72 characters | ||
-.B |
Disable alarm | ||
C | Move by Characters When UTF-8 enabled, move by entire UTF-8 runes (.F) | ||
-nC |
Move backwards n characters | ||
nC |
Move forward n characters | ||
.C | Call macro in buffer 2. | ||
.Cstring^Z |
Search for string in buffer 2 (2.Z). If the string is found, use the characters immediately following as the command. This acts as a “named subroutine”. The current command pointer is stacked before the new commands are interpreted. The sequence should end with command .R (return). If the end of buffer 2 is seen,the next commands are read from the keyboard (but the stacked command pointers are not removed). This feature is experimental (along with .R) | ||
D | Delete characters When UTF-8 enabled, delete entire UTF-8 runes (.F) | ||
-nD |
Delete backwards n characters | ||
nD |
Delete forward n characters | ||
.D | Eightbit If eightbit mode is set, the terminal is presumed to respond to eight bit codes in the buffer. (see .F) | ||
.D |
Enable 8-bit display output | ||
-.D |
7 bit only | ||
E | End edit | ||
E
| End and accept edits. Must be by itself. | ||
.E | SEEALL mode. For SCOPE (.S) | ||
.E |
Enable SEEALL. Spaces are shown as ‘.’ and line ends as ‘<’. | ||
-.E |
Disable SEEALL | ||
F | Find | ||
nFstring^Z |
Find nth occurrence of string. | ||
.F | UTF-8 Editing | ||
.F |
Enable UTF-8 edit (enables .D as well) | ||
-.F |
Disable UTF-8 edit. | ||
G | Increment or Decrement bar | ||
+G |
Increment vertical bar column | ||
-G |
Decrement vertical bar column | ||
2G |
Add 2 to vertical bar column | ||
.G | Set bar | ||
7.G |
Set vertical bar to column 7 (FORTRAN) | ||
0.G
| Remove vertical bar | ||
H | Home | ||
H |
Commit edits and rewind. Must be by itself. | ||
.H | Tabulation. Up to 20 tabs can be set. ^W in I command inserts spaces to next tabulation | ||
-.H |
Clear all tabs | ||
0.H 1.H .H |
Display tabs | ||
n.H |
Set tab at column n, or if already set, remove. | ||
I | Insert | ||
Istring^Z |
Insert string at current point | ||
I |
Bulk input mode (^Z to exit) If the I command is issued in uppercase, the string will be uppercased (even if -U is in effect). | ||
-I |
High impact I | ||
Istring<cr> |
Insert string with newline | ||
.I | Insert character | ||
n.I |
Insert character n | ||
26.I |
Insert ^Z | ||
12.I |
Insert form-feed | ||
0.I |
Insert NUL | ||
J | Juxtapose | ||
nJstring1^Zstring2^Zstring3^Z
|
Search for string1, replace with string2, and then erase until string3. | ||
.J | Set Extension | ||
n.J.extension^Zmajor^Zdisplay^Z
. -n appends to .M? help.
| Set extension n (0..127)|||
K | Kill lines | ||
0K |
Remove characters to front of line | ||
-nK |
Remove n previous lines | ||
nK |
Remove n lines | ||
K |
Remove to end of line, including end of line mark | ||
L | Move by Lines | ||
0L |
Move to beginning of line | ||
nL |
Move forward n lines | ||
-nL |
Move backward n lines | ||
.L | ^L in search translated to NL | ||
-.L |
Allow searching for ^L | ||
.L |
Translate ^L to NL (ED default) | ||
M | Macro | ||
nMcommands^Z |
Repeat commands n times | ||
.M | Mode (Edit modes below - there are also display modes: eg. SCHEME) | ||
.MTEXT^Z .M^Z
| Set mode TEXT | ||
.MFORTRAN^Z |
Set mode FORTRAN | ||
.MCOBOL^Z |
Set mode COBOL | ||
.MC^Z |
Set mode C | ||
.MSNOBOL4^Z |
Set mode SNOBOL4 | ||
.MLISP^Z |
Set mode LISP | ||
.MSHELL^Z |
Set mode SHELL | ||
.MPASCAL^Z |
Set mode PASCAL | ||
.MASSEMBLER^Z |
Set mode ASSEMBLER | ||
N | Nfind | ||
nNstring^Z |
Same as F, but if the string is not found, issues #W, 0A and reissues the find, until the end of input file or the string is found. | ||
.N | Open index file | ||
.Nfile^Z |
Open file which should contain lines with positive or negative integers. These are read in with the & argument, and usually represent relative lines. If the file argument is null, the index file is closed. Used to process lines from external utilities. Note that buffering is not controlled here at all (left to the operator). But, since buffering may be a concern, line numbers (or character positions) read from the index file should be relative and in ascending order. | ||
O | Original file | ||
O |
Cancel all edits and rewind Prompts Y/N, see .Y command. Must be by itself. | ||
P | Page | ||
0P |
Display page (16 lines) | ||
-nP |
Move backward n pages, display | ||
nP |
Move forward n pages, display | ||
Q | Quit edit | ||
Q |
Abandon edits. Prompts Y/N, see .Y command. Must be by itself. | ||
R | Read | ||
R^Z |
Read transfer file | ||
Rfile^Z |
Read named file | ||
.R | Return from macro. | ||
.R |
Pop command pointer from call stack (see .C). | ||
S | Substitute | ||
nSstring1^Zstring2^Z
|
Substitute n occurrences of string1 with string2. | ||
nSstring1^Zstring2<cr>
|
Substitute n occurrences of string1 with
string2, adding newline. S, F, N, J commands replace ^L with newline (see .L). | ||
.S | Scope mode | ||
.S |
Enter full screen scope mode, or, if in scope mode, refresh screen | ||
-.S |
Leave scope mode | ||
2.S |
Enter non-interactive scope mode | ||
3..21.S |
Scope mode, with 3 to 21 lines for command area | ||
0.S |
From 2.S go back to interactive scope mode (because .S is 1.S) | ||
T | Type | ||
0T |
Display line begin to point | ||
T |
Display point to line end | ||
nT |
Display n lines | ||
-nT |
Display previous n lines | ||
.T | Tabs | ||
n.T |
Set tab expansion to n columns | ||
0T |
Disable tab expansion. Tab displayed as ^I | ||
U | Uppercase | ||
U |
Enable uppercasing | ||
-U |
Disable uppercasing | ||
V | Verify | ||
V |
Enable line number prompt | ||
-V |
Disable line number prompt | ||
0V |
Display buffer used, line number | ||
2V |
Display flags | ||
3V |
Display buffer changed | ||
4V |
Display filenames | ||
.V | Scan/Alter | ||
n.Vexpr |
Call external scan utility. This allows SNOBOL4
patterns to be used for find or replace. For example .V
'word' searches for word in the specified lines. Instead
of positioning the current point, the line deltas are
recorded in the default transfer file $ . The
.N$ command is issued to open the transfer
file as the source for & arguments, allowing
subsequent &L commands to skip to the next found
occurence. If an = sign is in the argument,
the operation is a replace. The first occurence matching on
each line is replaced. If a /G flag (global) is specified,
all occurences on each line are replaced. Any SNOBOL4 pattern
can be used. This feature is still experimental
| ||
W | Write lines to output file | ||
0W |
Write lines until buffer is 1/2 empty | ||
#W |
Write all lines | ||
nW |
Write n lines | ||
-nW |
Write n pages | ||
X | Transfer | ||
0X |
Empty transfer file | ||
nX |
Append n lines to transfer file. | ||
.X | Set transfer file name. | ||
.Xfile |
Set transfer (X) file to file. This file will be deleted on 0X. Exiting CPMED via E or Q will not delete this file (but the default transfer file $ is erased). This complements Rfile and allows transfer of data between two files. The file is not immediately used - opening and writing is deferred until the X command is used. This name will also be used as the default name for the R command. Use .X^Z to reset to the default transfer file name. | ||
Y | UNDO. Fail if stack empty. | ||
Y |
Undo last command | ||
.Y | Yes (prompt control) | ||
-.Y |
Enable Y/N prompts | ||
.Y |
Disable Y/N prompts, assume Y | ||
Z | Sleep | ||
nZ |
Sleep for n seconds | ||
.Z | Alternate buffer | ||
n.Z |
Select edit buffer n seconds. Buffer 1 is the primary, and is controlled by REGION. Buffer 2 is the alternate. The alternate buffer is 16K bytes in length (or REGION2). Reading and writing must be done with R and X. | ||
! | Shell | ||
!command |
Execute command | ||
.! | Filter lines | ||
10.!sort |
Sort the next 10 lines | ||
-10.!sort |
Sort the next 10 lines, do not replace. New lines in transfer file (see R) | ||
@ | Goto Mark | ||
0@ |
Goto Mark 0 | ||
.@ | Goto Character Mark | ||
1.@ |
Goto Character Mark 1 Character marks are set by the # command as well. Mark 1 is automatically set by searching commands (F, S and J). | ||
# | Set Mark | ||
0# |
Set Mark 0 (both character and line) | ||
$ | Match string | ||
% | Indent/Outdent | ||
% |
Increase indent | ||
-2% |
Outdent two levels | ||
^ | Result to argument | ||
& | .N next element to argument | ||
* | Shelf | ||
0*string |
Store string to shelf | ||
n* |
Store n characters from buffer to shelf (^F to retrieve). Shelf is maximum 1024 characters. | ||
-*string^Z |
Store to shelf, up to first character of string | ||
( | Start Block | ||
) | End Block | ||
_ | Complement Execution | ||
= | Evaluate expression | ||
? | Help | ||
n? |
Display help page n (1..10). If n is negative, append to help page. | ||
/ | Repeat search | ||
n/ |
Repeat last F, S, J, or N command n times | ||
; | DO NOT ASSIGN This is a ^Z in CE edit commands | ||
: | Go to line | ||
n: |
Go to line n | ||
, | Brace match | ||
, |
Go to matching brace ([{<>}]) | ||
.. | Source file | ||
..file |
Read editing commands from file. Can be nested up to 20 deep | ||
.3 | ASCII-64 mode (TTY ASR 33) | ||
.3 |
ASCII-64 | ||
-.3 |
ASCII-127 256, or UTF-8 | ||
.8 | CP/M-80 Compatibility - Write CR/LF, ^Z | ||
.8 |
CP/M-80 - Enable CR/LF on writing. In this mode, files are terminated with ^Z, padded to 128 bytes, and line ends are CR/LF. This is OFF normally (enable for CP/M-80 file compatibility). | ||
-.8 |
Unix - LF only on writing | ||
> | Result to Execution. After an = expression, the RESULT is set, and this can be transferred to the EXECUTION indicator. | ||
< | Branch back. Branch to the enclosing (. |
Unlike CP/M-80 ED
, line end is a single
character. Files can be saved in a CP/M-80 compatible format,
by issuing .R
prior to writing. Normally,
-.R
is used, which doesn't pad files, and uses
a single LF as a line terminator. If .R
is in
effect when reading, the first ^Z
in the file
acts as the end of file. CR characters are stripped as well.
The bar is a vertical ruler. It fills space and tab whitespace with a | in one column down the screen, including the ruler. This allows for easy and consistent code alignment.
@
in addressing means compute delta lines between
current point and mark.
0V
(no line number prompting) may be useful
when editing material with line numbers such as BASIC
code. V
is on by default.
Each line is delimited by the end-line character, which
is an LF (^J
). If in scope mode, and a line
fills the horizontal screen exactly, there is still one more
character, which is the line end. The point can be positioned
at the line-end, and, in the case of a full line, the last
character will be replaced in scope mode (visually) with
a highlight space.
Under CP/M-80, the end of line was indicated by two characters - CR followed by LF.
Some useful commands and equivalences:
nMXK |
J^Z^Z^P^J^Z == KI^P^J^Z
(except at end of buffer) |
Istring^Z == S^Zstring^Z |
0TT |
.YQ |
0KK == 0LK |
-#C == B |
#C == -B |
0KK == 0LK |
Some commands (E
, Q
, O
and H
) must be entered on a line by themselves,
unless the .Y
flag is enabled. This also prevents
prompting, making it possible to script CPMED sessions.
^Z
and ^D
are ignored,
but terminate a command string. This is important in
conjunction with the M
command. For example:
4MLT^ZLT
. M
commands do not nest.
2.S
non-interactive scope mode is used to
compensate for the extreme inefficiency of scope mode. When
working over a slow link, normal scope mode may be too slow.
2.S
mode only updates the visual area on
.S
, ^V
, Page Up and Page Down.
This means that the editor is still somewhat “visual” but
doesn't spend effort updating the screen. It is also possible
to shrink the update area. Normally, 6 lines are used for the
command area, but this can be increased (or decreased). If
increased, less lines are used for the update area, making
updates faster:
15.S
uses 15 lines for the command area, leaving 9 lines for the update area. A “page” (P command) is still 16 lines.
CPMED
creates backup files named after the
original, with a .bak
added to the end. Editing
x.c
produces x.c.bak
for its
backup. If two filenames are specified on the command line,
the first is the input file and the second is the output
file. In this case, no .bak
file is produced
(4V
shows the active filenames). With two files
(input and output), the H
command (Head, or save
and re-edit), performs a flip-flop – the output file
becomes the new input and the old input becomes the output.
There are many commands for entering new copy:
<tab>text
| Insert a line |
Itext
| Insert text with newline at current point |
Itext^Z
| Insert text at current point |
65.I |
Insert character by code |
I |
Bulk insert |
-I |
Bulk insert, full screen update |
| Insert | Insert key, issues -i command |
I
and -I
are only distinguished in
scope mode. The main reason for this is that I simply added
entry methods based on my immediate needs. These commands
are probably not optimal. I
allows indent but
can't backspace over a newline.
In scope mode, I
clears the characters
under the CP, and enters bulk input mode. The screen
is not fully updated, but characters are displayed as
entered. Interpretation of the normal line input characters
is done, but no handling autoindent, indent or outdent is done.
-I
updates the scope view on each character,
fully. This allows all visual editing, along with the ability
to backspace over newlines. Backspacing is limited to the
beginning of the -I
entry. ^T
and
^G
are handled by executing the indent and outdent
code. ^X
and ^U
erase back to the
last newline, allowing easy removal of extra indentation. This
insertion mode is very expensive in terms of scope updates,
but works well on a local screen. I
works without
performance problems over slow communications lines.
After a F
(find) command, the point can be
positioned to the start of search string using:
Ftext^Z.@
Marks 2 through 9 are general purpose. Mark 1 is the start
of a F S
or J
match. Mark 1 will be
overwritten by these three commands. Mark 0 is also available,
but is reserved for other editor internal uses.
The shelf is a string that can have contents put on via the
*
command.
| 0*string | Save string to shelf |
| 10* | Put next 10 characters from buffer to shelf |
The shelf can be retrieved into the current command by using
^F
. The command to put the contents into the
shelf must be executed before the shelf can be retrieved. This
is an experimental feature, and is subject to change. The
main motivation is to be able to search for UTF-8 sequences,
and to be able to manipulate text in the buffer in a more
convenient way. The problem with this implementation is that
the ^F
command is only interpreted at command
entry, and not execution. This make it impossible to use
in a program block. ^F
expansion should be
delayed! But, this means that ^P^F
wouldn't
work correctly. So, for program use, the shelf has to be
“pre-stored” in a separate command line. This is not yet
a fully useful feature.
sh
stty
(if not LINUX)
Terminal handling uses stty
to control echo,
break, etc. rather than coding directly. stty
is also used to determine the actual geometry of the terminal
(we still use VT100 style direct terminal codes, but the
terminal can be of a different size). The shell must be
capable of supporting “()” grouping, “2>”, “|”,
“;” and “&&”, and the “/tmp” directory
should be writable (sh
and bash
should be suitable shells).
If -DLINUX is specified when building, stty
is not used, but termios
and ioctl
functions are.
Some of the function keys and keypad (PC style) are bound to commands:
| <F1> | ? |
| <Insert> | -i |
| <Delete> | D |
| <Home> | 0L |
| <End> | L-C |
| <Page Up> | -P |
| <Page Down> | P |
| ← | -C (arrow left) |
| → | C (arrow right) |
| ↑ | -L (arrow up) |
| ↓ | L (arrow down) |
| ctrl ← | control-left, word left macro |
| ctrl → | control-right, word right macro |
Word left and right are implemented via macro. The macro for word right is:
($^J^Z$ ^Z$^I^Z=OR OR NOT^Z>C<) ($^J^Z$ ^Z$^I^Z=OR OR^Z>C<)
Test current character for newline, space or tab, if not, move character right and loop. Then test newline/space/tab, if it is, move right and loop.
and the macro for word left is:
($^J^Z$ ^Z$^I^Z=OR OR NOT^Z>-C<) ($^J^Z$ ^Z$^I^Z=OR OR^Z>-C<) ($^J^Z$ ^Z$^I^Z=OR OR NOT^Z>-C<)C
Test newline/space/tab, if not, move left and loop. Test
newline/space/tab, if so, move left and loop. Test
newline/space/tab, if not, move left and loop. Finally,
move right one character. The final move should move to
the beginning of the word. (^I
is tab, and
^Z
is control-z, ^J
is newline). To
enter a ^Z
, ^J
or ^I
,
^P
can be used as a prefix to suppress the normal
meaning of the key. These two macros are built into the editor,
though. See macro file nw (next word). When the macro file is
read, we can insert a ^P
to allow ^J
to be used a a “data character”. Again, this technique
is used in nw. Also, nw shows how to save the incoming repeat
count and apply it to a M
(macro) command.
When in -I
insert mode, the Insert key leaves
the insertion (like ^Z
or ^D
keys).
Immediate keys cancel the input being done on the command line
(and do so without feedback), and immediately execute the
function they are bound to. This means that repetition counts
do not work for immediate keys. For example 5C
moves 5 characters forward, but 5 followed by right arrow does
not. Word motion is only bound to the control left and
right keys, and cannot be repeated. This matches my thought
processes – I am either “ad-hoc” editing, or I am
thinking about the efficiency of edits. I don't combine these
two thought modes, so this implementation “works for me”.
The M
command provides basic counted
macros. These, however, don't nest, nor provide any
conditionals.
CPMED provides for a very simple programming language. Programs look like line noise, because the language is designed to be trivial to interpret.
( commands )
The parentheses block commands. These nest, to provide for looping and flow control:
( commands ( nested commands ) yet more commands ) ( ... )
There is an execution flag. When ON, command execution progresses as usual. When OFF, commands are parsed but not executed until the matching ) is seen, at which time execution returns to normal.
The editor has a four register stack for evaluation. This allows RPN expressions to be built. Currently, two evaluation commands exist: RPN expression (described below) and the string test operator:
$string^Z
String test puts a 1 into the register stack if the string matches at the current buffer location, otherwise a 0.
The > operator transfers the RPN stack X register into the execution flag. This allows for conditional execution. Thus:
($ ^Z>D)
will delete the current character if and only if it is a space.
The _
operator inverts the execution flag (but
is skipped at more deeply nested block levels).
( $ ^Z> D _ I*^Z )
deletes the current character if it is a space, otherwise it inserts an asterisk.
The <
operator branches back to the matching
(
, providing basic looping capability.
The =
operator (RPN expression) provides basic
arithmetic. RPN notation is used (and, note that ASCII-64 is
the character set, so & | ~
are not used):
| number | Numeric constant (255) | |
| Hhex | Hex constant (HFF) | |
| Ooctal | Octal constant (O377) | |
| + - * / | Basic arithmetic | |
| ? | Character at current point | |
| # | Number at current point | |
| AND OR | And, or (binary) | |
| NOT | Not, 0→1, non-0→ 0 (NOT NOT→boolean) | |
| NEG | Negate X = -X | |
| COMP | Complement (binary) | |
| SWAP | Swap X, Y | |
| DUP | Dup T = Z, Z = Y, Y = X | |
| ROLL | Roll X = Y, Y = Z, Z = T, T = X | |
| = < | Compare (equal, less) | |
| P | Print (decimal, signed) | |
| HP | Hex print | |
| OP | Octal print | |
| $A..Z | Retrieve variable A through Z | |
| >A..Z | Store variable A through Z | |
| $[internal] | Retrieve internal variable | |
| >[internal] | Store internal variable |
| [CP] | Current point |
| [MP] | Max point (end of buffer) |
| [LN] | Line number |
| [TOP] | Top line number |
| [N] | Number prefix |
| [N2] [N3] [N4] | Old number prefix |
| [KEYBS] | Key for backspace (8) |
| [KEYRUB] | Key for rubout (127) |
| [ROWS] | Display rows (24) |
| [COLS] | Display columns (80) |
| [BROWS] | Display bottom rows (6, includes ruler) |
| [CCOL] | Scope cursor column |
| [CROW] | Scope cursor row |
| [SP] | Start of buffer for scope |
| [X] [Y] [Z] [T] | RPN stack |
| [C0]..[C9] | Character marks |
| [L0]..[L9] | Line marks |
These can be read with $[CP]
, or more simply
[CP]
. And set with >[CP]
. Careful
with modifying CP directly; LN is not adjusted automatically!
CP should be modified using C
, L
,
F
, or B
only.
Spaces can be used as separators:
*=HFF 12 + P 267
The six numeric comparision operators can be derived as follows:
| Operator | How | Description |
|---|---|---|
| x == y | x y = | x == y |
| x != y | x y = NOT | !(x == y) |
| x < y | x y < | x < y |
| x <= y | x y SWAP < NOT | !(y < x) |
| x > y | x y SWAP < | y < x |
| x >= y | x y < NOT | !(x < y) |
The result register can also be used as a numeric leadin by
specifying ^
as the command count. For example
*3T *=3^Z^T (this is: = 3 control-z ^ T)
both type 3 lines.
The following program will uppercase a letter:
*= ? 97 - 65 + ^Z D ^.I
Note that each “program” is limited to a single input
string, and that the parenthesis must be matched within
a single line. =
begins an expression,
?
retrieves the character at the CP. 97
is the ASCII code for ‘a’. 65 is the ASCII code for
‘A’. D
removes the character from the
buffer. ^
introduces the result of the expression
as the argument to .I
which inserts the character
represented by its ASCII argument.
More programming features will be added, and even parts of the editor itself are coded as macros (word left and right).
*( $^P^J^Z >| C < )
moves to the next end-of-line (L
command). With
start of buffer and end of buffer in expressions, we may be
able to synthesize more editor commands as macros. Note that
C
and -C
fail silently at the bottom
and top of the edit buffer.
Programs are most useful when entered into SOURCE files
(..file
) to be called on when needed. These
SOURCE files are to be collected into CELIB, or can be in
the current directory if only applicable to the local project.
Any commands following ..
are removed. This
means that SOURCE is not useful in a macro. The file is not
read until the current command is exhausted.
..copyright
for example), and text
editing (55..t
to position to column 55). and
formatting (..f
to format a paragraph). See the
“readme” file in that directory for more details.
CPMED
supports UTF-8 in a limited
way. +/-C
and +/-D
will “skip”
10xxxxxx (binary) bytes to ensure that the current position
is always on a UTF-8 begin code. D
deletes
the entire UTF-8 sequence. As well, UTF-8 will be displayed
assuming the terminal is capable.
CPMED
has recently been built on Linux, Solaris
(SPARC32) and HP-UX (PA-RISC2.0)
| Linux | gcc -Os -DLINUX -o cpmed cpmed.c |
| Solaris | gcc -Os -o cpmed cpmed.c |
| HP-UX | cc -DHP_UX -o cpmed cpmed.c |
If LINUX is not defined, stty
will be used to put
the terminal into raw mode, and determine lines/columns. On
Linux, termios
and ioctl
are used.
popen()
is used if LINUX is not defined
to determine terminal size (reading stty
output). There is, of course, a better way, but this does work.
On HP_UX, the select()
prototype is in
time.h
. This requires -DHP_UX
.
Other platforms are easily supported, but this is my current “working set” of systems.
The .!
command pipes one or more lines
through an external filter, and replaces the lines with
the filter results. Some CELIB macros use external filters
(..sp
, ..di
and ..f
for example). Here are some of the programs that can be used
(not exhaustive, just examples):
| banner | big letters |
| boxes | draw boxes |
| cdecl | C declarations |
| diction | check diction |
| expand | tabs to spaces |
| fmt | format |
| indent | indent c |
| sort | sort |
| spell | spell check |
| unexpand | spaces to tabs |
For example, the above list was sorted using the command
10.!sort
-*^P^J
transfers the remainder of the line to
the shelf. ^F
will retrieve the line to the
command line, where it can be executed. For example consider
the following. The editor command will select the program,
and send it to the bas
interpreter. The edit
script will then position after the code to the result area,
and update the result.
L -6.!bas 6L K r 10 sum = 0 20 for i = 1 to 10 30 sum = sum + i 40 next 50 print "Sum of 1 through 10 =", sum run Sum of 1 through 10 = 55
The 0V
command provides free space and total space
in the buffer, and the current line number. 2V
displays all flags. 3V
indicates whether the
buffer has been changed. 4V
displays the filenames
for current input, output and backup. Output may be a temporary
file (if only one filename was specified). .H
displays tabulations that have been set.
1257: *0v 2047887/2097152 BUF 1 1257: 1257: *2v -U+V1.S-.Y-.D-.R-.3+.L-.E-.F8.A-.B8.T 1257: *3v BUFFER CHANGED 1257: *4v INPUT: README OUTPUT: /tmp/filepvD5u2 BACK: README.bak TRANSFER: $ 1257: *.h TAB: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1257: *
This indicates that we have almost 2 megabytes free in the
buffer, that our current line is 1257. We are editing
in the primary buffer. Uppercase is false, verbose
prompting (with line numbers) is on, we are in scope
mode, command prompting is enabled (for Q
,
O
, etc.), we are not in eight-bit display
mode, not in CP/M-80 file mode, not in ASCII-64 mode,
^L
will be translated to newline in find commands,
SEEALL is off, UTF-8 is off, we
have autoindent enabled, and our indent amount is 8. Margin
bell is off, and tabs are expanded to 8 columns. The buffer
has been changed. The input filename is README
,
backup to README.bak
, and the write file is a
temporary file /tmp/filepvD5u2
. The transfer
file is $
. No tabulations have been set.
The following features are considered experimental. They may be changed. UTF-8 support is not yet complete. The alternate editor buffer (2.Z) has been included to provide storage for named macros. The SHELF (*) feature (^F retrieval) isn't fully useful. .C/.R (call and return macro) are experimental. .N and & argument introduced to allow external programs to generate an index for processing by the editor.
These are used by the scan
utility to find lines by patterns. The lines can be altered,
killed, or otherwise manipulated.


How to use Gothic Damage Calculator
- Use radio button to choose between Gothic 1 and Gothic 2 (choosing Gothic 2 will provide accurate results for both vanilla and Night of the Raven expansion).
- Using spinners, input all relevant information about the Nameless Hero, his weapon and the target, you are trying to hit.
- Only spinners with blue border and green background are 'relevant'. Other spinners will not affect the results.
- Click on the 'Run' button to see the results.
Using spinners:
- You can choose to either input the number directly into the input field, or use the up/down buttons to increment/decrement the number.
- You can only use integers greater than or equal to zero, i.e. {0, 1, 2, ...}.
- Each spinner has defined minimum and maximum value:
- 0–100: weapon skills, bonus weapon skill, lightning hit chance,
- 0–5,000: strength, dexterity, weapon damage, lightning damage, melee armor, ranged armor,
- 1–5,000: number of hits,
- 1–1,000,000: hitpoints.


Reports binary, conditional or instanceof expressions consisting of multiple terms with different operators
without parentheses. Such expressions can be unclear because not every developer is intimately familiar with all the precedence rules
of the different operators. This inspection has a quickfix which adds clarifying parentheses.
New in 11, Powered by InspectionGadgets


module Builder:sig
..end
type
t
tid
of the block. It is a user
responsibility to preserve the uniqueness of tidentifiers
throughout the program instance.val create : ?tid:tid ->
?phis:int -> ?defs:int -> ?jmps:int -> unit -> t
create ~tid ~phis ~defs ~jmp ()
creates a block builder.
If tid
parameter is specified, then the new block will
have this tid. If any of phis
, defs
or jmps
parameters
are specified, the provtided number would be used as a hint
of the expected amount of the corresponding entries. Since
it is the hint, it can mismatch with the actual size. The
hint must be a positive number.val init : ?same_tid:bool ->
?copy_phis:bool ->
?copy_defs:bool ->
?copy_jmps:bool -> blk term -> t
init blk
creates a builder based on an existing
block. If copy_phis
, copy_defs
or copy_jmps
is true
(defaults to false
), then prepopulate builder with
corresponding terms from block blk
. If same_tid
is true
(default), then a resulting block will have the same tid
as block blk
. Otherwise, a fresh new tid
will be created.val add_def : t -> def term -> unit
appends a jump
val add_jmp : t -> jmp term -> unit
val add_phi : t -> phi term -> unit
val add_elt : t -> Blk.elt -> unit
val result : t -> blk term


Introduction A single test case follows a pattern. Setup the data, invoke the function or method with the arguments and assert the return data or the state changes. A function will have a minimum of one or more test cases for various success and failure cases.
Here is an example implementation of wc command for a single file that returns number of words, lines, and characters for an ASCII text file.
 The very next day, I tried the Keras yolov3 model available in the Github. It was trained on the coco80 dataset and could detect person but not the face touch.
V1 Training The original Keras implementation lacked documentation to train fromscratch or transfer learning.
[Read More]
Capture all browser HTTP[s] calls to load a web page
How does one find out what network calls, browser requests to load web pages?
The simple method - download the HTML page, parse the page, find out all the network calls using web parsers like beautifulsoup.
The shortcoming in the method, what about the network calls made by your browser before requesting the web page? For example, firefox makes a call to ocsp.digicert.com to obtain revocation status on digital certificates. The protocol is Online Certificate Status Protocol.
[Read More]
How long do Python Postgres tools take to load data?
Data is crucial for all applications. While fetching a significant amount of data from database multiple times, faster data load times improve performance.
The post considers tools like SQLAlchemy statement, SQLAlchemy ORM, Pscopg2, psql for measuring latency. And to measure the python tool timing, jupyter notebook’s timeit is used. Psql is for the lowest time taken reference.
Table Structure annotation=> \d data; Table "public.data" Column | Type | Modifiers --------+-----------+--------------------------------------------------- id | integer | not null default nextval('data_id_seq'::regclass) value | integer | label | integer | x | integer[] | y | integer[] | Indexes: "data_pkey" PRIMARY KEY, btree (id) "ix_data_label" btree (label) annotation=> select count(*) from data; count --------- 1050475 (1 row) SQLAlchemy ORM Declaration class Data(Base): __tablename__ = 'data' id = Column(Integer, primary_key=True) value = Column(Integer) # 0 => Training, 1 => test label = Column(Integer, default=0, index=True) x = Column(postgresql.
[Read More]
Debugging Python multiprocessing program with strace
Debugging is a time consuming and brain draining process. It’s essential part of learning and writing maintainable code. Every person has their way of debugging, approaches and tools. Sometimes you can view the traceback, pull the code from memory, and find a quick fix. Some other times, you opt different tricks like the print statement, debugger, and rubber duck method.
Debugging multi-processing bug in Python is hard because of various reasons.
[Read More]
Book Review: Software Architecture with Python
The book Software Architecture with Python is by Anand B Pillai. The book explains various aspects of software architecture like testability, performance, scaling, concurrency and design patterns.
The book has ten chapters. The first chapter speaks about different architect roles like solution architect, enterprise architect, technical architect what is the role of an architect and difference between design and architecture. The book covers two lesser spoken topics debugging and code security which I liked.
[Read More]
Return Postgres data as JSON in Python
Postgres supports JSON and JSONB for a couple of years now. The support for JSON-functions landed in version 9.2. These functions let Postgres server to return JSON serialized data. This is a handy feature. Consider a case; Python client fetches 20 records from Postgres. The client converts the data returned by the server to tuple/dict/proxy. The application or web server converts tuple again back to JSON and sends to the client.
[Read More]
Expose jupyter notebook over the network
What is the Jupyter notebook?
The Jupyter Notebook is a web application that allows you to create and share documents that contain live code, equations, visualisations and explanatory text.
The definition is from the official site. I use IPython/Jupyter shell all time. If you haven’t tried, spend 30 minutes and witness the power!
At times, I want to share some code snippet with folks in the same building during work, workshop or training.
[Read More]
RC Week 0010
This week has been a mixed ride with the torrent client. I completed the two pending features seeding and UDP tracker. The torrent client has a major issue with downloading larger torrent file like ubuntu iso file. The client starts the downloads from a set of peers and slowly halts at sock.recv after exchanging a handful of packets. At this juncture CPU spikes to 100% when sock.recv blocks. Initially, the code relied on asyncio only features, now the code uses curio library.
[Read More]
RC week 0001
This week, I made considerable progress on the BitTorrent client which I started a week back. The client is in a usable state to download the data from the swarm. The source code is available on GitHub. The project uses Python 3.5 async/await and asyncio. I presented the torrent client in RC Thursday five minute presentation evening slot. Here is the link to the slides.
Here is quick video demo recorded with asciinema.
[Read More]


Preparing Your Hosts¶
Setting PATH¶
The PATH for the root user on each host must contain the following directories:
- /bin
- /sbin
- /usr/bin
- /usr/sbin
These should all be included by default in a fresh CentOS 7.x installation.
Ensuring Host Access¶
The Agave Platform installer requires a user that has access to all hosts b jcvbp. If you want to run the installer as a non-root user, passwordless sudo rights must be configured on each destination host.
For example, you can generate an SSH key on the host where you will invoke the installation process:
# ssh-keygen Do not use a password.
An easy way to distribute your SSH keys is by using a bash loop:
# for host in auth.agave core.agave db.agave ; do \
ssh-copy-id -i ~/.ssh/id_rsa.pub $host; \
done
Modify the host names in the above command according to your configuration.
Installing Base Packages¶
The Agave Platform installer will install all necessary packages on the host on first run. On each subsequent run, the installer will ensure the packages are present and up to date. The following packages will be installed:
- libselinux-python
- git
- cronie
- net-tools
- bind-utils
- iftop
- bash-completion
- psacct
Installing Docker¶
The Agave Platform installer will also install and configure the Docker daemon on the hosts. Only trusted registries are enabled by default. If you will be pulling images from a registry with a self-signed cert, or cert signed by an untrusted CA, you should add the ip address or subnet of any insecure registries you plan to use to the docker_insecure_registries
list variable in your inventory file. This will tell the installer to include those values as --insecure-registry
parameters to the Docker daemon startup command on each host. The –insecure-registry option instructs the Docker daemon to trust any Docker registry on the indicated subnet, rather than requiring a certificate.
...
[agave:vars]
...
docker_insecure_registries:
- <IP_ADDRESS>
- <IP_ADDRESS>/32
...
Warning
Once this value is set, changing it will require restarting the Docker service on each host. This will result in all running containers being stopped. Keep this in mind when deciding to use an insecure registry for your images.
Configuring Docker Storage¶
The containers running the components of the Agave Platform are stored in Docker’s storage back end. This storage is ephemeral and separate from any persistent storage allocated to meet the needs of your applications. With Ephemeral storage, container-saved data is lost when the container is removed. With persistent storage, container-saved data remains if the container is removed.
The Agave Platform installer configures persistent storage for each system that runs a container daemon. In HA installations, the persistent storage will leverage a NFS mount on each host. In standard installations, container data will be persisted using volume mounts to the host file system.
Managing Container Logs¶
The Agave Platform installer will configure Docker to use the json-file
logging driver by default. You can manage this by configuring Docker’s json-file logging driver to restrict the max log file size to 5MB and a maximum of 5 files.
Note
Future versions of the installer will consolidate all logging into a fluentd forwarder running natively on the host. You will then have the option of consuming the fluentd stream in your preferred tool. Until then, logs are written to local disk and rotated via logrotate
.


Robert wrote an excellent report on the Mascot AC-AC adapter. Robert found that the AC-AC adapter gives a maximum phase error of 5.75º.
I'm just wondering: if we could spend a little more money (say less than £40), are there AC-AC adapters that would provide less phase error?
Re: Is it possible to improve on the AC-AC adapter?
I'd like to find a safe way to ditch the transformer completely and use a resistive divider. That gets rid of SO many problems (phase errors, wave distortion, accurate zero detection with non-symetric waveforms, etc.)
There's just the nagging problem of lack of galvanic isolation, which many find important!
Is there another way to make a resistive divider safe?
P.
Re: Is it possible to improve on the AC-AC adapter?
Paul, some months ago, I spent a while playing around with a 240VAC resistive divider and have posted a few results using this arrangement. Albeit rather scary (no earths, otherwise the house would trip!), the rig worked fine but its performance was found to be no better than when using a transformer. For calculating/diverting real power, I now feel confident that it's not worth going down this route. PM me if you'd like to exchange ideas about this.
When dealing with more complex aspects such as Power Factor, or the current signatures from individual appliances, it may be more beneficial to use some kind of direct measurement. But that's only my unofficial opinion, not that of any panel :-)
Re: Is it possible to improve on the AC-AC adapter?
For Mk2a type applications I'm sure a transformer is fine, but OpenEnergyMonitor is about much more than that (sorry!). At its heart it's a measurement system, and as such accuracy is important.
P.
Re: Is it possible to improve on the AC-AC adapter?
Sorry - that sounded harsh and a bit grumpy. Wasn't meant that way!
P.
Re: Is it possible to improve on the AC-AC adapter?
At its heart it's a measurement system, and as such accuracy is important.
I understood that the initiators of this project wanted it to be non-invasive and safe (for amateurs to install). If you drop these requirements, then you are free to use resistive dividers and shunt current measurement.
And there might also be legal problems (liability questions and loss of insurance) if you as an amateur 'work' on the electrical wiring or if you connect DIY-equipment to your installation (this would at least be a problem here in Germany).
Using a ready-made plug in AC-adapter (with isolating transformer!) and CT clamps is 100% safe regarding these issues.
Re: Is it possible to improve on the AC-AC adapter?
For my own project, I definitely need galvanic isolation.
Robert ran some simulations of using a capacitive probe to detect voltage (instead of an AC-AC adapter). Robert reported that: "Simulation shows that the phase angle [for a capacitance probe] is quite possibly better than the AC-AC adapter - certainly it doesn't change with the applied voltage"
So a capacitive probe might provide better measurement of phase angle. (A phase shift isn't too much of a problem if it's a constant shift across the voltage range so we can easily compensate for it).
Are there "better" transformers that we could consider? (by "better" I mean minimum phase shift and maximum frequency response)? e.g. a toroidal transformer?
Re: Is it possible to improve on the AC-AC adapter?
That's what the Eco-Eye device does. I think it assumes a fixed voltage, which is kind-of fine I guess because for most of us the voltage won't be fluctuating by more than about 1%. The change in phase angle (detectable by the foil) is much more important, and helps to convert the measured VAs into the Ws that our electricity meters (and bills!) understand.
Don't get me wrong - if you CAN measure voltage too then great, but I reckon phase angle CAN be more important, and doesn't need a transformer.
P.
Re: Is it possible to improve on the AC-AC adapter?
The Eco-eye monitor requires the user to input the value of their mains voltage; this value is then used for all power calculations.
While developing my Mk2a code, it became very evident that our mains voltage can vary considerably during the day. If I calibrate my system correctly at 3pm, its power values are likely to have shifted by several percent by the evening. Supply meters take voltage variation into account, so for accurate measurements of real power I feel sure that voltage should be measured as well as current.
The effect of introducing time-shift into the voltage waveform was surprisingly small when I measured it a few months ago (between the 4 and 8 minute points on the video). Although PHASECAL has a very minor effect when calculating real power, it will more directly affect any measurements that are made of Power Factor and the like.
Re: Is it possible to improve on the AC-AC adapter?
I expect Robert will reply soon himself but his simulations suggest that a capacitive probe should be able to measure voltage (as well as phase).
Re: Is it possible to improve on the AC-AC adapter?
OK, sorry I've been otherwise occupied so far today....
The capacitive "transformer" (as it is called by the Power Transmission people) is generally and I think exclusively used on high voltage systems, so measuring the voltage with it is no problem so long as the physical arrangement remains unchanged, that is it is dimensionally stable and it is properly screened to remove changes in capacitance due to the proximity of other objects. (The high voltage capacitor is normally an integral part of the transformer or switchgear bushings - look up the links in the post that Jack quoted).
While I don't have an Eco-Eye and I don't know their design philosophy, I'd guess that they don't use it to measure the voltage because they have no control over the mechanical arrangement of the foil capacitor.
I don't see why a toroidal transformer should necessarily be better than a conventional E-I one. As I've said many times, the designer's art is to get the maximum output of acceptable quality for minimum cost. If you're rectifying the current to get d.c, the waveform isn't at all important, neither is phase shift. Neither (usually) are losses - they're the customer's problem, so the designer goes for the minimum amount of copper and iron to give him the best profit.
The only alternative that I can think of is that you could have a custom wound transformer designed and made. I have one - I believe it was the phase reference transformer out of a thyristor drive, and it has significantly less phase shift and distortion than any of the adapter-type transformers that I've seen. And for its VA rating, it is positively huge. Clearly, it is working way down the B-H curve where non-linearities are small. It is undoubtedly British made, dating from the late 1960's, but has no maker's name on it. I don't know of a firm that might be prepared to do this, nor the likely cost.
Jorg's point about safety is spot on. I understand that many emonTx kits go into schools, and the thought of a bunch of school-children messing about with anything not 101% safe and foolproof doesn't bear thinking about. Which pretty much rules out anything not sealed in a box.
Re: Is it possible to improve on the AC-AC adapter?
Just a quick note: Texas Instruments have a 7-page PDF on "current-transformer phase-shift compensation and calibration" using a digital finite impulse response (FIR) filter: http://www.ti.com/general/docs/lit/getliterature.tsp?literatureNumber=sl...
I presume this could be easily adapted for AC-AC adapter phase shift compensation. (I know emonLib does some phase-shift compensation using linear interpolation)
Re: Is it possible to improve on the AC-AC adapter?
I've quickly scanned through the note but it doesn't appear to offer a solution to the problem of the phase shift changing with load current (in the case of the c.t.); or system voltage (in the case of the v.t.). The inherent problem is that on the grounds of cost and availability, we're not specifying and using measurement grade parts, but we are expecting measurement-grade results.
Re: Is it possible to improve on the AC-AC adapter?
Hi!
I'm interested too, on a way to avoid the AC-AC adapter. Yes, I know is very dangerous for -not electrician- people. I've found this isolated linear sensing ic: HCPL-7520
http://www.avagotech.com/docs/AV02-0956EN
Thinking of a "PRO" Oem Version with 3 current inputs and 3 voltage inputs.. will be amazing. It's possible?
Regards
Re: Is it possible to improve on the AC-AC adapter?
For those confident and competent enough to build one, I think that I may have found the answer. Not that it is cheaper than the Mascot or any safer than the Mascot but it should be as safe as the Mascot transformer solution when in use, if correctly and carefully built. It will be a design based on the Vishay IL300.
This is my first stab at the circuit. I intend to order the IL300 shortly and I think it will be appropriate to change the circuit in order to get the output dc biased in the right place. To do this I have decided that the drive to the LED should be inverted then the 'secondary' can be inverted too. None of the secondary side circuitry needs (or arguably should) be included in the same enclosure - it belongs with the cpu.
Last week I thought I would try the idea 'in-principle' by using two conventional opto-isolators with LED's in series. It worked but the linearity was poor (to say the least) and the dc drifted with temperature !
I probably should not be suggesting that anyone tries this but I will let you know how I get on in a week or two.
Edit: I seem to be having some difficulty presenting that .pdf file
Re: Is it possible to improve on the AC-AC adapter?
I've just noticed that the Mascot adapter is no longer stocked in the shop, it's been replaced by a different brand for which no test results appear to be available :(
Did you tick the "List" box after attaching your .pdf file? If not, you can always Edit your post and do so later.
Re: Is it possible to improve on the AC-AC adapter?
Thanks Robin. Its there now.
Re: Is it possible to improve on the AC-AC adapter?
"I've just noticed that the Mascot adapter is no longer stocked in the shop, it's been replaced by a different brand for which no test results appear to be available :("
If somebody would like to send me one, I'll be quite happy to run the tests on it and write another report.
Re: Is it possible to improve on the AC-AC adapter?
Later this weekend I hope to publish on a new thread my solution for a transformerless Galvanically Isolated Voltage Monitor
Think I will call it 'GIVmon' :-)
Re: Is it possible to improve on the AC-AC adapter?
Rob, I await your test results with interest. In my limited experience, the quality of the AC/AC adaptor makes minimal difference to the ability of an energy-bucket type router to divert surplus power correctly. The one I use for heating our water is the worst of any that I've tested; its distortion is far worse than the Mascot.
The only reason I'm still using it is that I don't believe any other one would give better performance. Tests a few months ago with the same adaptor showed a good degree of import/export balance when I temporarily fitted a disc-style meter, and that's all that really matters for this application.
My No 1 rig has a pair of Rich's PCBs, along with a smart (donated) pcb transformer. In due course, that rig will hopefully end up in a box on the garage wall. In the meantime, it does an excellent job of checking out any new builds that I post on the forum. It's only our DHW that has to manage with the original breadboard lash-up!
Re: Is it possible to improve on the AC-AC adapter?
The GIVmon is all very well, I know it's possible to do better in a variety of ways, but it's not a viable option for many, for all the obvious reasons.
Re: Is it possible to improve on the AC-AC adapter?
Yes, test results are everything. AND My MFT1502 is calling for another 8 AA batteries ....
Hmm... I was hoping to do a 1KV insulation test between input and output but my model won't do it even with new batteries for some reason. Will have to be satisfied with 500v dc for the time being. Yep, that's OK.
BTW I will update my profile later this evening since for an item like this, folk will need to be satisfied with my credentials!
I think it would also be appropriate for me to send my prototype to Robert Wall if he would like to give it a try? (Maybe in a few days time you will PM me with your address.) Always good to have a second opinion on these things. I shall be uncommonly fortunate if nothing needs more attention.
Enough for the moment I'm sure many of you would like to see it. Will have to make do with stills for the time being. I've never done utube(?) unlike you Robin :-)
Re: Is it possible to improve on the AC-AC adapter?
YouTube is no problem. It's the concept of "credentials" that's worrying me!


This application takes a metric tire size and returns the size in inches. The purpose is to answer questions like, "I have LT235/75R15s on my truck, how much clearance will 31s buy me?" and "I know 30s will fit my Jeep with out a lift, but will a LT235/75R15?". All this can be done with out breaking out the tape measure! You must have a Java compatible browser to run this Applet.
Metric tire sizes are made up of four components: prefix, width, aspect ratio, and wheel size. It takes three of these components to calculate the diameter of the tire. It sure is not a very straight forward sizing convention.
The prefix is used to indicate general use of the tire. The tire input field trys to ignore the prefix and if your prefix causes an error, just don't input it. The Gear and Tire Applet currently will successfully ignore 'P' for passenger car and 'LT' for light truck. When in doubt, drop the prefix.
The width simply the width of the tire in mm. For example the tire size P215/75R15 has a width of 215mm.
The next component is the aspect ratio. The aspect ratio is the percentage of the width that makes up the sidewall of the tire. In the above example the aspect ratio is 75 or 75%, so the sidewall height is 75% of 215 or 161.25mm. If you want the diameter of the tire, you need to take into acount that the diameter of the tire passes two sections of the side wall. This means the sidewall takes up 161.25*2 or 322.5mm of the diameter.
The next component is the wheel size. In the above example the wheel size is 15". If you convert the total sidewall into inches you get 322.5mm*0.03937in/mm or about 12.6". Add that to wheel size and you get the diameter 15"+12.6" is 27.6". So a P215/75R15 tire has a diameter of about 27.6".


Chance to live in popular Mid Devon village close to sought-after school
This four-bed family house in Sampford Peverell has a lot to offer
by Tina Penberthy-HutchingsThe Mid Devon village of Sampford Peverell has long been a sought-after area with house hunters, but just what makes it so popular?
With a thriving community, excellent transport links, and walks along the picturesque Grand Western Canal all on the doorstep, the village has a lot to offer.
Even better, if you are a family looking for a home in the catchment area of one of the region’s most sought-after secondary schools, Sampford Peverell is also within the Uffculme School catchment.
At the end of a cul de sac in a small development, No.18 Cornlands is a spacious four-bedroom house just a short walk from the centre of the village.
Boasting some far-reaching countryside views and fitted with solar panels, the detached property offers driveway parking, a single garage, and plenty of living accommodation.
Step inside and you will find an entrance hall, cloakroom, a sitting room opening to the conservatory, and a kitchen and breakfast room.
For more formal dining there is a separate dining room, and completing the ground-floor accommodation is a handy utility room.
The first floor is home to the four double bedrooms, accessed from a central landing which also leads to the family bathroom. Helping to cut the morning bathroom queues, the master bedroom has its own en-suite.
Outside, the rear garden is split into two distinct areas. A large sunny patio sits immediately to the rear of the house.
Bordered by a pretty picket fence, the patio could be a perfect place for summer entertaining with direct access into the kitchen and the conservatory creating a great indoor outdoor feel.
Beyond the patio, a gently sloping lawn area is a great area for children to let off steam or for you to simply relax with a cuppa in the sunshine.
When you want to stretch your legs further, No.18 Cornlands is just a short walk from the Grand Western Canal and the lovely country walks along its towpath.
Head into the village centre and you will discover an active community with a village hall, a primary school, a lovely old church, a post office and store, doctors’ surgery and two pubs.
For those looking for an easy commute, Sampford Peverell is home to Tiverton Parkway railway station, as well as being about two miles from junction 27 of the M5 motorway.
The village also has a good bus service into Tiverton which lies about seven miles to the west.
No.18 Cornlands is on the market for offers in the region of £345,000.
To find out more and to view this fantastic family home, call Seddons in Tiverton on 01884 253500.
To search for more properties for sale across Devon why not visit the DevonLive.com property channel? Click here to find your new home .


{% extends "layout.html" %}
{% block body %}
{% if member %}
| Member ID | {{ member.member_id }} |
| App ID | {{ member.app_id }} |
| UDID | {{ member.udid }} |
| Device Platform | {{ member.device_platform }} |
| Service Platform | {{ member.service_platform }} |
| Push Notification | {{ member.push_notification }} |
| GCM Token | {{ member.gcm_token }} |
| Facebook |
| ID | {{ member.facebook_id }} |
| Email | {{ member.facebook_email }} |
|
| Status | {{ member.status }} |
| Reg Date | {{ member.reg_date }} |
| Last Information |
| Device Platform | {{ member.last_device_platform }} |
| Service Platform | {{ member.last_service_platform }} |
| Login Date | {{ member.last_login_date }} |
|
{% else %}
등록된 회원이 없습니다
{% endif %}
{% endblock %}


Defines core classes for the Convex Hull problem.
Given a set of points P in a two-dimensional plane, the convex hull is
the smallest convex shape that fully encloses all points in P. The hull
is convex because a line between any 2 points within it lies totally
within the hull.
The convex hull computation is specified by the following API description:
public interface IConvexHull {
/**
* Return the computed convex hull for the input set of IPoint objects.
*
* Points must have at least three points to do anything meaningful. If
* it does not, then the sorted array is returned as the "hull".
*
* Some implementations may be able to work if duplicate points are found,
* but the set should contain distinct IPoint objects.
*
* @param points a set of (n ≥ 3) two dimensional points.
*/
public IPoint[] compute (IPoint[] points);
}
The hull is formed by a clockwise ordering of h points L0 … Lh–1. The first point
L0 is typically the leftmost point in the set P (although any point can be the
start). Each sequence of three hull points Li, Li+1, Li+2 creates
a right turn; note that this property holds for Lh–2, Lh–1, L0 as well.


Notoane: 'It's quite clear it wasn't a penalty'
Cape Town - South Africa U-23 head coach David Notoane said it is clear that the referee made an error in awarding a penalty to Egypt in their 3-0 defeat in the semi-finals of the U-23 AFCON on Tuesday.
Abdel Rahman Magdy scored two late goals to secure a win for The Pharaohs after captain Ramadan Sobhy had broken the deadlock by converting a controversial 59th-minute penalty.
The referee pointed to the penalty spot despite the South African defender being clearly outside of the box which handed Egypt an undeserved lead.
"The penalty awarded in the 59th minute had an effect on my players from that point onward," Notoane said. "I have video footage of that incident and it is quite clear that it was not a penalty.
"I would though like to congratulate Egypt on booking their place to next year's Summer Olympic Games We hope to join them as we will now face Ghana for that final Olympic qualification spot.
"Coming into this match we started with Luther Singh playing as our striker because we wanted to break down their defence with speed in the final third.
"My charges played really well, however, lacked a goal or two to complement their efforts in the first-half."
South Africa's chances though of qualifying for next year's Tokyo Summer Olympic Games are still within their grasp as they face Ghana in a third-place play-off on November 22 at Cairo Stadium.
Kick-off is at 16:30 (SA time).
Compiled by Baden Gillion