HTML Extractor
-
this presentation is the program HTML Extractor (
hx
)
-
it contains all source code that is needed to build the executable
-
but the code is spread over multiple slides
-
to form an extreme form of Literate Programming
-
that may be called Slideware-Programming (
SWP
)
-
Have fun!
What is hx
?
-
hx
is a program that parses a Markdown document and extracts source code or an executable program out of it
-
think of it as a very powerful macro processor that combines, extends and orders small fragments of code
-
but also it generates a HTML documentation like the one you are currently reading
Why use Markdown document?
-
Markdown documents are structured text documents
-
it contains sections at different levels, paragraphs and code snippets
-
hx
formats the sections and code snippets as slides of a very big slide show
-
these slides should be decorated with notes
SWP
≠ Literate Programming
-
SWP
should not document a finished program
-
but it should document the process of creating a program instead
-
after every slide you can generate the code from all the slides that you have read
-
and without peeking in the future a runnable program must result
-
so it does not contain features that are described the later slides
A very top-down view of hx
-
in the first code slide contains the highest view of the
hx
program
-
while not very interesting, it contains a lot of commands that show how
hx
works
6
@Def(file: ../src/hx.cpp)
@put(global elements)
int main(int argc, const char **argv) {
@put(main body)
}
@End(file: ../src/hx.cpp)
-
hx
is written in C++ and consists of one source file hx.cpp
-
global elements like types, macros and functions are defined before the central
main
function is defined
-
these elements and the body of the
main
function will be defined and refined in later slides
Commands
-
the first code slide has three
hx
commands: @Def
, @put
, and @End
-
each command starts with an ampersand (
@
), some letters and an argument block
-
the argument block consists of an opening parenthesis, the argument value, and a closing parenthesis
-
for now assume, that no closing parenthesis or ampersand is part of the argument value
Fragments
-
hx
processes code fragments
-
a fragment starts with an opening command like
@Def
-
and ends with a matching
@End
or @end
closing command
-
the name of the fragment is the argument value of the opening command
-
and must be the same as the argument value of the closing command
Defined Fragments
-
three fragments are defined on the first code page
-
they have the names
file: hx.cpp
, global elements
, and main body
-
not all
hx
commands use their argument value as fragment name
-
but the three presented so far all do
Including fragments
-
a fragment can be included into another fragment with the
@put
command
-
you must not include a fragment that directly or indirectly includes the current fragment, because that will result in a cycle
-
hx
prevents cyclic includes
-
the inclusion will happen after all slides are processed
-
so it is possible to include a fragment that is not defined yet
Naming files
-
fragments whose name start with
file:
are special
-
hx
writes them into files
-
the file name is the rest of the argument value after the
file:
prefix
-
the first code slide creates one fragment that is written into the file named
hx.cpp
Generating the first source code
-
if we stop here and run
hx
, the following code will be generated
13
int main(int argc, const char **argv) {
}
-
the unknown fragments are noted in the output of
hx
-
but the file compiles without errors
-
so it does not do much
Steps in main
-
the next code slides identify multiple steps to perform in the
main
function
15
@def(main body)
#if ! NDEBUG
@put(perform unit-tests)
#endif
@end(main body)
-
the unit-tests are performed at every start of the program
-
unless a release version is build
-
the use of
@def
instead of @Def
is no mistake
-
@Def
defines a global fragment that is visible in all input files
-
@def
defines a local fragment that is only visible in the current input file
-
and in all input files that are included directly or indirectly by this input file for the first time
16
@add(main body)
@put(process arguments)
@end(main body)
-
after the unit-tests
main
parses the arguments passed to it from the command line
-
@add
extends an existing local fragment
-
the ability of macros to grow with time is borrowed from Literate Programming
-
but is is far more important in
SWP
, as a slide provides only limited space
17
@add(main body)
@put(read source files)
@end(main body)
-
next the source files are read into a fragment tree
-
here a lot of interesting things are happening but right now it will expand to nothing as nothing is described yet
18
@add(main body)
@put(serialize fragments)
@end(main body)
-
in the next step
hx
writes the content of every file fragment in its designated file
19
@add(main body)
@put(write HTML file)
@end(main body)
-
and lastly the HTML documentation is generated
20
@def(global elements)
@put(includes)
@end(global elements)
-
hx
defines a global fragment for included files
Next steps
-
the following slides refer to documents that document the next steps of
hx
-
follow them in order so that you do not miss important concepts
22
@add(global elements)
class Frag;
class Frag_Ref;
Frag *find_frag(const std::string &path, const std::string &key,
bool local, std::string *got_path = nullptr
);
Frag *find_frag(const Frag_Ref &ref, std::string *got_path = nullptr);
Frag &get_frag(const std::string &path,
const std::string &key, bool local
);
Frag &get_frag(const Frag_Ref &ref);
#include <map>
using Frag_Map = std::map<std::string, Frag>;
Frag_Map &frag_map(const std::string &in);
Frag_Map &frag_map();
void split_frag(const std::string &name, Frag *meta,
std::map<std::string, std::string> &&values
);
void clear_frags();
void eval_metas();
@end(global elements)
-
defines the mechanisms of reading files line by line
-
the
@inc
command includes a different input file at the current position
-
the file is read only once, no matter how often it is included
-
you can click on the argument value in the HTML documentation to navigate to the documentation from this file
-
the input is split into blocks
-
a block has a type, a value and optional notes
-
blocks are separated by newlines
-
defines logging mechanism
-
fragments are flexible macro definitions
-
they can be extended or replaced in later parts of the input file
-
fragments can be used before they are defined
-
if they are not defined in the end, they will be expanded to nothing
-
so even a partial program can be generated
-
the input class contains all the blocks and fragments that the input file consists of
-
the fragments are used to generate the code
-
the blocks are used to generate the documentation
-
the blocks are mostly needed for the interactive editor that is block-based
Parsing command line arguments
-
parses the command line arguments element by element
29
@def(process arguments)
for (int i { 1 }; i < argc; ++i) {
std::string arg { argv[i] };
@put(process argument)
@put(process file argument)
ASSERT_MSG(false, "unknown argument [" << argv[i] << ']');
}
@end(process arguments)
-
the arguments are processed one by one
-
if an argument is processed successfully, the program short-cuts the loop
-
so the end of the loop is an indicator that an unknown argument occurred.
-
if it is not a known argument it may be a file name.
30
@add(global elements)
std::string stylesheet { "slides/slides.css" };
@end(global elements)
-
for the HTML-output a CSS-stylesheet is used
-
an argument can specify the used file
-
but a default is presented here
31
@def(process argument) {
static const std::string prefix { "--css=" };
if (arg.substr(0, prefix.length()) == prefix) {
stylesheet = arg.substr(prefix.length());
continue;
}
} @end(process argument)
-
sets a new stylesheet path
32
@Def(needed by read_sources)
int blockLimit = -1;
@End(needed by read_sources)
-
limits the number of blocks that will be processed
33
@add(process argument) {
static const std::string prefix { "--limit=" };
if (arg.substr(0, prefix.length()) == prefix) {
blockLimit = std::stoi(arg.substr(prefix.length()));
continue;
}
} @end(process argument)
-
the user can limit the number of blocks that will be processed
-
so the user can verify that subsets are working properly
34
@def(process file argument)
inputs.add(arg);
continue;
@end(process file argument)
-
if no other argument pattern matches the argument is treated as input file
-
from these files slides and source code are generated
Read input files
-
the code of this section reads input files, extracts the fragments and blocks and establishes their interdependencies
36
@Add(inputs prereqs)
using SI = std::string::const_iterator;
@End(inputs prereqs)
-
the code uses string iterators at a lot of places
-
so it defines a shorthand to reduce clutter on the slides
37
@Add(needed by read_sources)
void process_char(
Frag *frag, char ch, const std::string &cur_path, int cur_line
) {
@put(process char)
}
@End(needed by read_sources)
-
adds a single character to the content of a fragment
38
@Add(process line)
auto end = line.cend();
std::string cur_path = inputs.cur().path();
int cur_line = inputs.cur().line();
std::map<std::string, std::string> cmd_values;
for (auto i = line.cbegin(); i != end; ++i) {
if (skip_spaces) {
if (*i <= ' ') { continue; }
skip_spaces = false;
}
@mul(process special chars)
process_char(frag, *i, cur_path, cur_line);
}
if (! skip_spaces) {
process_char(frag, '\n', cur_path, cur_line);
}
@End(process line)
-
reads each character in the current line
-
special characters are processed first
-
if the character was not special, it will be added to the current active fragment
39
@Def(additional read vars)
Frag *frag { nullptr };
@End(additional read vars)
-
the
frag
pointer signals if the current line is inside a fragment in a code sequence (not nullptr
)
-
at the beginning there is no active fragment
-
so the pointer is
nullptr
40
@def(process char)
if (frag) {
frag->add(ch, cur_path, cur_line);
}
@end(process char)
-
if there is an active fragment, the character will be added to its contents
-
based on the current input file and line number the fragment may open a new block
41
@def(process special chars)
if (*i == '@') {
auto nb = i + 1;
auto ne = nb;
@put(cmd prefix)
if (ne != end && ne != nb) {
std::string name { nb, ne };
@put(cmd argument)
}
}
@end(process special chars)
-
special sequences start with
@
-
it follows a name and an argument in parenthesis
-
if the input is not matching it is not treated as a syntax error
-
but as normal characters that are not treated special
42
@def(cmd prefix)
while (ne != end && *ne != '(') {
if (! isalpha(*ne)) {
ne = end;
break;
}
++ne;
}
@end(cmd prefix)
-
check that the name contains only letters
-
and is followed by an opening parenthesis
43
@def(cmd argument)
auto ab = ne + 1; auto ae = ab;
while (ae != end && *ae != ')') {
if (*ae == '@') {
@put(handle at in cmd arg)
}
++ae;
}
if (ae != end) {
std::string arg {ab, ae};
@put(cmd found)
continue;
}
@end(cmd argument)
-
arguments are read until the closing parenthesis
-
characters in the argument can be escaped by prefixing them with
@
-
that is needed to allow for the closing parenthesis in the argument
44
@def(handle at in cmd arg)
if (++ae == end) { break; }
if (isalpha(*ae)) {
@put(handle cmd in cmd arg)
}
@end(handle at in cmd arg)
45
@def(handle cmd in cmd arg)
auto ac { ae };
while (isalpha(*ac)) {
++ac; if (ac == end) { break; }
}
if (ac != end && *ac == '(') {
int cnt = 1; ++ac;
while (ac != end && cnt != 0) {
if (*ac == '(') { ++cnt; }
if (*ac == ')') { --cnt; }
++ac;
}
if (cnt == 0) {
ae = ac - 1;
}
}
@end(handle cmd in cmd arg)
46
@def(cmd found)
i = ae;
bool outside = ! frag;
do {
if (outside && ! blockLimit) {
break;
}
@put(do special cmd)
@put(do default cmd)
} while (false);
if (blockLimit && outside && frag) {
--blockLimit;
}
@end(cmd found)
-
if the block limit is reached, nothing will be processed
-
if the command was not a functional command, it will be replaced by its argument in source code
-
for example formatting hints are only used for syntax highlighting
-
and can be ignored in generated source code
-
after processing a block the code adjusts the limit
47
@Add(needed by read_sources)
inline void expand_cmd_arg(
Frag *f, const std::string &arg,
const std::string cur_path, int cur_line
) {
auto b = arg.begin();
auto e = arg.end();
@put(expand loop)
}
@End(needed by read_sources)
-
performs the default expansion of an unknown command
48
@def(do default cmd)
if (frag) {
if (frag->is_meta()) {
auto f { cur_path };
auto l { cur_line };
frag->add('@', f, l);
frag->add(name, f, l);
frag->add('(', f, l);
frag->add(arg, f, l);
frag->add(')', f, l);
} else {
expand_cmd_arg(frag, arg, cur_path, cur_line);
}
}
if (name == "b") {
skip_spaces = true;
}
@end(do default cmd)
-
if the command was not a functional command, it will be replaced by its argument in source code
49
@add(includes)
#include <algorithm>
@end(includes)
-
std::find
is used on the next slide
50
@def(expand loop)
while (b != e) {
auto x = std::find(b, e, '@');
@put(expand before)
if (x != e) {
b = x + 1;
@put(expand escaped)
} else {
b = e;
}
}
@end(expand loop)
-
the code can not copy the argument directly
-
the argument may contain escaped sequences starting with
@
-
the code will unescape them
51
@def(expand before)
f->add(std::string { b, x }, cur_path, cur_line);
@end(expand before)
-
copy everything that is before the current iterator
52
@def(expand escaped)
if (b != e) {
f->add(*b, cur_path, cur_line);
++b;
}
@end(expand escaped)
-
add escaped char, if there is one
53
@Add(needed by read_sources)
#define ASSERT_NOT_FRAG() \
ASSERT_MSG(! frag, '@' << \
name << "(" << arg << \
") in frag [" << \
frag->name << ']' \
)
@End(needed by read_sources)
-
raise error, if command is in an active fragment
54
@Add(needed by read_sources)
#define CHECK_NOT_DEFINED() \
if (isPopulatedFrag(frag)) { \
WARN_MSG("frag [" << arg << \
"] already defined" \
); \
}
@End(needed by read_sources)
-
warn, if fragment is already filled with some content
55
@def(do special cmd)
if (name == "def") {
ASSERT_NOT_FRAG();
frag = &get_frag(cur_path, arg, true);
CHECK_NOT_DEFINED();
break;
}
@end(do special cmd)
-
creates a new fragment
-
fragment must not be created multiple times
56
@Add(needed by read_sources)
#define ASSERT_FRAG() \
ASSERT_MSG(frag, '@' << \
name << "(" << arg << \
") in frag [" << \
frag->name << ']' \
)
@End(needed by read_sources)
-
raise error, if command is not in an active fragment
57
@add(do special cmd) {
auto i { cmd_values.find(name) };
if (i != cmd_values.end()) {
frag->add(i->second, cur_path, cur_line);
break;
}
} @end(do special cmd)
58
@add(do special cmd)
if (name == "end" || name == "End") {
ASSERT_FRAG();
if (frag->is_meta()) {
std::string pattern;
std::map<std::string, std::string> values;
parse_args(arg, pattern, values);
if (frag->name == pattern) {
frag = nullptr;
} else {
auto f { cur_path };
auto l { cur_line };
frag->add('@', f, l);
frag->add(name, f, l);
frag->add('(', f, l);
frag->add(arg, f, l);
frag->add(')', f, l);
}
} else {
@put(frag names must match)
frag = nullptr;
}
break;
}
@end(do special cmd)
-
interrupts the active fragment
59
@def(frag names must match)
ASSERT_MSG(frag->name == arg,
"closing [" << arg << "] != [" << frag->name << ']'
);
@end(frag names must match)
-
the name of the fragment must match the command argument
60
@Add(needed by read_sources)
#define CHECK_DEFINED() \
if (! isPopulatedFrag(frag)) { \
WARN_MSG("frag [" << arg << \
"] not defined" \
); \
}
@End(needed by read_sources)
-
warn, if fragment is not filled with some content
61
@add(do special cmd)
if (name == "add") {
if (frag && frag->is_meta()) {
auto f { cur_path };
auto l { cur_line };
frag->add('@', f, l);
frag->add(name, f, l);
frag->add('(', f, l);
frag->add(arg, f, l);
frag->add(')', f, l);
} else {
ASSERT_NOT_FRAG();
frag = &get_frag(cur_path, arg, true);
CHECK_DEFINED();
}
break;
}
@end(do special cmd)
-
reopens an existing fragment
-
more content can be added to it
62
@Add(needed by read_sources)
void parse_args(const std::string &arg, std::string &pattern,
std::map<std::string, std::string> &values
) {
for (unsigned i { 0 }; i < arg.size(); ++i) {
if (arg[i] == '@') {
unsigned j { i + 1 };
while (j < arg.size() && isalpha(arg[j])) { ++j; }
if (j > i + 1 && j < arg.size() && arg[j] == '(') {
int cnt { 1 };
unsigned k { j + 1 };
for (; k < arg.size() && cnt; ++k) {
if (arg[k] == '(') { ++cnt; }
if (arg[k] == ')') { --cnt; }
}
if (! cnt) {
std::string key { arg.substr(i + 1, j - i - 1) };
std::string value { arg.substr(j + 1, k - j - 2) };
values[key] = value;
pattern += '@';
pattern += key;
pattern += '(';
i = k - 1;
}
}
}
pattern += arg[i];
}
}
@End(needed by read_sources)
63
@add(do special cmd)
if (name == "put") {
if (! frag && arg.find('@') != std::string::npos) {
std::string pattern;
std::map<std::string, std::string> values;
parse_args(arg, pattern, values);
Frag *sub = &get_frag(cur_path, pattern, true);
sub->addMultiple();
split_frag(pattern, sub, std::move(values));
} else {
ASSERT_MSG(frag, "@put" << "(" << arg << ") not in frag");
Frag *sub = &get_frag(cur_path, arg, true);
ASSERT(sub);
@mul(check frag ex. count)
sub->addExpand();
frag->add(Frag_Ref { cur_path, arg, true });
}
break;
}
@end(do special cmd)
-
searches the fragment and integrates it
-
if the fragment is not found, a new one is created to be populated later
64
@def(check frag ex. count)
if (sub->expands()) {
std::cerr << "multiple expands of [" << sub->name << "]\n";
}
if (sub->multiples()) {
std::cerr << "expand after mult of [" << sub->name << "]\n";
}
@end(check frag ex. count)
-
if the fragment was already expanded, an error message is generated
-
also if the fragment was expanded in multiple mode
65
@add(do special cmd)
if (name == "inc") {
ASSERT_MSG(! frag, "include in frag [" << frag->name << ']');
if (! inputs.has(arg)) {
inputs.push(arg);
}
break;
}
@end(do special cmd)
-
includes another input file
-
opens the file and pushes it on the stack of open file
-
files that were are already included are ignored
66
@add(do special cmd)
if (name == "mul") {
ASSERT_MSG(frag, "@mul not in frag");
Frag *sub = &get_frag(cur_path, arg, true);
if (sub) {
@mul(check for prev expands)
sub->addMultiple();
frag->add(Frag_Ref { cur_path, arg, true });
}
break;
}
@end(do special cmd)
-
expands a fragment multiple times
67
@def(check for prev expands)
if (sub->expands()) {
std::cerr << "multiple after expand of [" << sub->name << "]\n";
}
@end(check for prev expands)
-
when a multiple expanded fragment was already expanded with a normal
@put
an error message is printed
68
@add(do special cmd)
if (name == "Def") {
@put(do Def)
break;
}
@end(do special cmd)
-
creates a new fragment in global namespace
69
@def(do Def)
ASSERT_MSG(! frag, "@Def in frag [" << frag->name << ']');
frag = &get_frag(cur_path, arg, false);
if (isPopulatedFrag(frag)) {
std::cerr << "Frag [" << arg << "] already defined\n";
}
@end(do Def)
-
if the fragment already exists, an error message is printed
70
@add(do special cmd)
if (name == "Add") {
@put(do Add)
break;
}
@end(do special cmd)
-
extends a global fragment
71
@def(do Add)
ASSERT_MSG(! frag, "@Add in frag [" << frag->name << ']');
frag = &get_frag(cur_path, arg, false);
if (! isPopulatedFrag(frag)) {
std::cerr << "Frag [" << arg << "] not defined\n";
}
@end(do Add)
-
a global fragment is any fragment that is defined in the global namespace or in an input file that includes the current input file
-
if the fragment is not defined, an error message is printed
72
@add(do special cmd)
if (name == "rep") {
ASSERT_MSG(! frag, "@rep in frag [" << frag->name << ']');
frag = &get_frag(cur_path, arg, true);
@mul(clear frag)
break;
}
@end(do special cmd)
-
replaces the content of a local fragment
73
@add(do special cmd)
if (name == "Rep") {
ASSERT_MSG(! frag, "@Rep in frag [" << frag->name << ']');
frag = &get_frag(cur_path, arg, false);
@mul(clear frag)
break;
}
@end(do special cmd)
-
replace the content of a global fragment
74
@def(clear frag)
ASSERT_MSG(frag, "frag [" << name << "] not defined");
frag->clear();
@end(clear frag)
-
clears the content of a fragment
-
if the fragment is not defined, an error message is printed
75
@add(do special cmd)
if (name == "Put") {
@put(do Put)
break;
}
@end(do special cmd)
-
inserts a global fragment in the current fragment
76
@def(do Put)
ASSERT_MSG(frag, "@Put not in frag");
Frag *sub = &get_frag(cur_path, arg, false);
if (sub) {
@mul(check frag ex. count)
sub->addExpand();
frag->add(Frag_Ref { cur_path, arg, false });
}
@end(do Put)
-
check that the fragment is not already expanded
77
@add(do special cmd)
if (name == "Mul") {
@put(do Mul)
break;
}
@end(do special cmd)
-
inserts a global fragment multiple times
78
@def(do Mul)
ASSERT_MSG(frag, "@Mul not in frag");
Frag *sub = &get_frag(cur_path, arg, false);
if (sub) {
@mul(check for prev expands)
sub->addMultiple();
frag->add(Frag_Ref { cur_path, arg, false });
}
@end(do Mul)
-
check that the fragment is not already used in a single expand
79
@add(do special cmd)
if (name == "priv") {
ASSERT_MSG(frag, "@priv not in frag");
@put(process private frag)
break;
}
@end(do special cmd)
-
creates a private identifier
-
the identifier is based on the argument, but extended with a hash-code based on the name and current input file name
80
@add(includes)
#include <functional>
#include <sstream>
@end(includes)
81
@def(process private frag)
std::hash<std::string> h;
auto cur { h(cur_path + ':' + arg) & 0x7fffffff };
@end(process private frag)
-
hash the current path and argument
-
mask the hash to a positive integer
82
@add(process private frag)
std::ostringstream hashed;
hashed << "_private_" << cur << '_' << arg;
frag->add(hashed.str(), cur_path, cur_line);
@end(process private frag)
-
new identifier has a common prefix,
-
the hash,
-
and the original argument
83
@add(do special cmd)
if (name == "magic") {
ASSERT_MSG(frag, "@magic not in frag");
@put(process magic frag)
break;
}
@end(do special cmd)
-
create a hash value based on the argument and the current path
84
@def(process magic frag)
std::hash<std::string> h;
auto cur { h(cur_path + ':' + arg) & 0x7fffffff };
@end(process magic frag)
85
@add(process magic frag)
std::ostringstream value;
value << cur;
frag->add(value.str(), cur_path, cur_line);
@end(process magic frag)
-
add the hash value to the fragment
Serialize Fragments
-
generate source code by traversing the tree of all fragments that specify files
-
and write the contents into the files
87
@add(global elements)
@put(needed by files write)
void files_write() {
@put(files write)
}
@end(global elements)
-
write all files generated from fragments
88
@def(serialize fragments)
if (write_files) {
files_write();
}
@end(serialize fragments)
-
write files, if requested
89
@def(files write)
for (auto &i : frag_map()) {
const Frag *frag { &i.second };
std::string cur_path { };
std::string cur_name { i.first };
@mul(serialize frag)
}
@end(files write)
-
fragments that start with
file:
represent files
-
additional the code checks if fragments were expanded not often enough
90
@add(files write)
for (auto &j : inputs) {
std::string cur_path { j.first };
for (auto &i : frag_map(cur_path)) {
const std::string cur_name { i.first };
const Frag *frag { &i.second };
@mul(serialize frag)
}
}
@end(files write)
-
also look for
file:
fragments in the local fragments
-
so you should define file fragments as global to avoid overwriting of files
91
@def(serialize frag) {
if (frag->isFile(cur_name)) {
@put(write in file)
}
} @end(serialize frag)
-
fragments that start with
file:
represent files
-
additional the code checks if fragments were expanded not often enough
92
@add(serialize frag) {
int sum { frag->expands() + frag->multiples() };
if (sum <= 0) {
std::cerr << "frag [" << frag->name << "] not called\n";
}
} @end(serialize frag)
-
if a fragment was not expanded, an error message is be written
93
@add(serialize frag)
if (! isPopulatedFrag(frag)) {
std::cerr << "frag [" << frag->name << "] not populated\n";
}
@end(serialize frag)
-
if a fragment was expanded, but not defined, an error message is written
94
@def(needed by files write)
std::string file_name(const std::string &name) {
return name.substr(6);
}
@end(needed by files write)
-
command argument without
"file:"
prefix is the file name
95
@add(needed by files write)
bool file_changed(const std::string &name, const Frag &f, std::string cur_path) {
std::ifstream in { file_name(name).c_str() };
if (! check_frag(name, f, in, cur_path)) {
return true;
}
if (in.get() != EOF) {
return true;
}
return false;
}
@end(needed by files write)
-
check if the file will be changed
-
if the fragments serialize to the content of the file, it must not be rewritten
-
and the modification date can stay the same
96
@def(write in file)
if (file_changed(cur_name, *frag, cur_path)) {
std::ofstream out(file_name(cur_name).c_str());
serializeFrag(cur_name, *frag, out, cur_path);
}
@end(write in file)
-
write fragment to the specified file
97
@add(global elements)
@put(needed by files process)
void files_process() {
@put(files process)
}
@end(global elements)
-
serialize all files that are processed by external programs
-
instead of directly written out
98
@add(serialize fragments)
if (process_files) {
files_process();
}
@end(serialize fragments)
-
only process files if requested
99
@def(files process)
for (auto &i : frag_map()) {
const Frag *frag { &i.second };
const std::string cur_path;
const std::string cur_name = i.first;
@mul(serialize cmd)
}
@end(files process)
-
process commands that are key at root level
100
@add(files process)
for (auto &j : inputs) {
for (auto &i : frag_map(j.first)) {
const Frag *frag { &i.second };
const std::string cur_path = j.first;
const std::string cur_name = i.first;
@mul(serialize cmd)
}
}
@end(files process)
-
process commands that are defined at the top of source files
-
this behavior is deprecated
101
@def(needed by files process)
bool no_cmds = false;
@end(needed by files process)
-
there is an option to disable command processing
102
@def(serialize cmd) {
const std::string cmd { Frag::cmd(cur_name) };
if (cmd.size()) {
@put(write cmd in file)
}
} @end(serialize cmd)
-
a fragment is only processed, if its name matches a command invocation
103
@def(write cmd in file)
std::ostringstream out {};
serializeFrag(cur_name, *frag, out, cur_path);
std::string o { out.str() };
if (no_cmds) {
std::cout << o;
} else {
@put(do write cmd)
}
@end(write cmd in file)
-
pipe serialized fragment directly to the command
-
if debug mode is activated the fragment is written to
std::cout
instead
104
@def(do write cmd)
std::FILE *f { popen(cmd.c_str(), "w") };
if (f) {
std::fwrite(o.c_str(), o.size(), 1, f);
pclose(f);
}
@end(do write cmd)
-
open pipe and send fragment to it
105
@add(process argument) {
static const std::string prefix { "--no-cmds" };
if (arg == prefix) {
no_cmds = true;
continue;
}
} @end(process argument)
-
disable command execution with a command switch
-
the file will be serialized to
std::cout
instead
-
Interactive display of slides
-
parsing lines with commands entered by the user
-
handle range requests in the editor
-
handle write commands in the editor
-
handle adding of new elements in the editor
-
ncurses
interface for the editor
115
@add(global elements)
using Inputs_Frag_Map = std::map<std::string, Frag_Map>;
class Frag_State {
public:
std::unique_ptr<Frag_State> parent;
Inputs_Frag_Map state;
Frag_State(std::unique_ptr<Frag_State> &&p):
parent { std::move(p) }
{ }
Frag *meta = nullptr;
std::string meta_path;
std::string meta_name;
std::map<std::string, std::string> meta_values;
};
std::unique_ptr<Frag_State> all_frags_ =
std::move(std::make_unique<Frag_State>(nullptr));
Frag_State *cur_state_ = nullptr;
Frag_State &cur_state() {
return cur_state_ ? *cur_state_ : *all_frags_;
}
Frag *find_frag(Frag_State &state, const std::string &in,
const std::string &key
) {
auto got { state.state[in].find(key) };
if (got != state.state[in].end()) {
return &got->second;
}
if (state.parent) {
Frag *pg = find_frag(*state.parent, in, key);
if (pg) {
return &state.state[in].insert({
key, { key, pg }
}).first->second;
}
}
return nullptr;
}
Frag *find_frag(const std::string &in, const std::string &key) {
return find_frag(cur_state(), in, key);
}
Frag *find_frag_in_files(const std::string &path, const std::string &key,
std::string *got_path
) {
std::string p { path };
for (;;) {
Frag *f { find_frag(p, key) };
if (f) {
if (got_path) { *got_path = p; }
return f;
}
const Input &i { inputs[p] };
if (i.prev.empty()) { return nullptr; }
p = i.prev;
}
}
Frag *find_frag(const std::string &path, const std::string &key,
bool local, std::string *got_path
) {
if (local) {
if (got_path) { *got_path = path; }
return find_frag(path, key);
} else {
Frag *f { nullptr };
Input &i { inputs[path] };
if (! i.prev.empty()) {
f = find_frag_in_files(i.prev, key, got_path);
}
if (! f) {
f = find_frag(std::string { }, key);
if (f) {
if (got_path) { *got_path = std::string { }; }
}
}
return f;
}
}
Frag *find_frag(const Frag_Ref &ref, std::string *got_path) {
return find_frag(ref.path, ref.name, ref.local, got_path);
}
Frag &add_frag(Frag_State &state, const std::string &in,
const std::string &key
) {
Frag *prev { nullptr };
if (state.parent) {
prev = &add_frag(*state.parent, in, key);
}
Frag &res { state.state[in].insert({
key, { key, prev }
}).first->second };
return res;
}
Frag &add_frag(const std::string &in, const std::string &key) {
return add_frag(cur_state(), in, key);
}
Frag &get_frag(const std::string &path,
const std::string &key, bool local
) {
Frag *f { find_frag(path, key, local) };
if (f) { return *f; }
const std::string new_path { local ? path : std::string { } };
return add_frag(new_path, key);
}
Frag &get_frag(const Frag_Ref &ref) {
return get_frag(ref.path, ref.name, ref.local);
}
Frag_Map &frag_map(Frag_State &state, const std::string &in) {
Frag_Map &cur { state.state[in] };
if (state.parent) {
Frag_Map &prev { frag_map(*state.parent, in) };
for (auto &f: prev) {
if (cur.find(f.first) == cur.end()) {
cur.insert({ f.first, { f.first, &f.second } });
}
}
}
return cur;
}
Frag_Map &frag_map(const std::string &in) {
return frag_map(cur_state(), in);
}
Frag_Map &frag_map() {
return frag_map(std::string { });
}
void split_frag(const std::string &name, Frag *meta,
std::map<std::string, std::string> &&values
) {
Frag_State ¤t = *all_frags_;
current.meta = meta;
current.meta_path = inputs.open_head();
current.meta_values = std::move(values);
current.meta_name = name;
std::unique_ptr<Frag_State> n {
std::move(std::make_unique<Frag_State>(std::move(all_frags_)))
};
all_frags_ = std::move(n);
cur_state_ = nullptr;
}
void clear_frags() {
all_frags_ = std::move(std::make_unique<Frag_State>(nullptr));
cur_state_ = nullptr;
}
void eval_meta(Frag_State &fs) {
if (fs.parent) {
eval_meta(*fs.parent);
}
if (fs.meta) {
@put(apply meta)
}
}
void eval_metas() {
eval_meta(*all_frags_);
}
@end(global elements)
116
@def(apply meta)
std::ostringstream out;
serializeFrag(fs.meta_name, *fs.meta, out, fs.meta_path);
std::istringstream in { out.str() };
std::string line;
Frag *frag = nullptr;
std::string cur_path = fs.meta_path;
int cur_line { 1 };
auto &cmd_values = fs.meta_values;
cur_state_ = &fs;
bool skip_spaces { false };
while (std::getline(in, line)) {
auto end = line.cend();
for (auto i = line.cbegin(); i != end; ++i) {
if (skip_spaces) {
if (*i <= ' ') { continue; }
skip_spaces = false;
}
@mul(process special chars)
process_char(frag, *i, cur_path, cur_line);
}
if (! skip_spaces) {
process_char(frag, '\n', cur_path, cur_line);
}
}
cur_state_ = nullptr;
@end(apply meta)


Dashboard of the COVID-19 Virus Outbreak -
Worldwide
World COVID - 19 Status
Cases by Country Status.
Source: worldometer (NovelCOVID API)
Flag
Country
Cases
Today Cases
Deaths
Today Deaths
Recover
Active
Critical
Cases Per One Million


Documentation:
module_graphbuilder.
graphbuilder
Create visualization of program callgraph using graphviz
No args
module_cleanup.
cleanup
Remove .disasm and .svg files created by graphbuilder
module_hashmatch.
hashmatch
Match known library functions with opcode hash technique
module_exp_pid_match.
exp_pid_match
Experimentally match PID functions. Signatures-based detection where a binary is expected to contain specific constant values and have specific connections. See source code for more details.
module_pidargs.
pidargs
Find arguments to PID_FIXCYCLE calls using symbolic execution (angr)
module_analytics.
analytics
Print analytics of program


Domino Development - Back to Basics - Part 6: Better safe than sorry - Security
Continuing from Part 5, this installment will shed a light on security.
Domino applications are protected by a hirarchical control system. If you fail to pass one hierachy level's test, it doesn't matter if a lower level would be compatible to you current credentials. E.g. when a database would allow anonymous access, but the server is configured to require authentication, you must authenticate. To fully understand the options, sit back and recall the difference between authentication and authorization. The former establishes who you are, the later what you can do. Let's look at both parts:
Accessing Domino through http(s) (or SMTP, IMAP and POP) uses open standards based authentication. I will focus on the http(s) options here. When a resource is protected (more on that later) the user is presented with an authentication challenge. In its simplest form it is http BASIC authentication that prompts for a username and password. In web UIs this isn't en vogue anymore, but in REST based access pulling and pushing JSON or XML it is still quite popular, since it is simple to use.
The most prevalent form (pun intended) is form based authentication. If a protected resource requires higher access than the current known user (who is anonymous before logging in), the user is redirected to a login page, where username and password are requested. This authentication can be per server or for a group of servers using LTPA or 3rd party plug-ins.
Users typically are listed in the Domino Directory or any compatible LDAP directory configured as authentication source. Users on Domino mail need to be in the Domino directory for mail routing to work.
A typical (structural) mistake: trying to use a remote 3rd party LDAP which creates additional network latency and single point of failure (the remote LDAP). When your Domino application server is running, your directory service is available, I wouldn't step away from this robustness. If your users strategically are maintained in a more fragile directory, use TDI to keep them in sync.
The final option to authenticate users is the use of X509 certificates. This requires the public X509 key to reside in the directory and the private key in the user's browser. I haven't seen that in large rollouts since it is a pain to administrate.
Anyway, as a result of an authentication, a user is identified with an X500 compatible name:
CN=Firstname LastName/OU=OrgUnit4/OU=OrgUnit3/OU=OrgUnit2/OU=OrgUnit1/O=Organisation/C=Country
Country (/C) and the Organisation Units (/OU) are optional. Typically we see 1-2 OrgUnits in use. They are practical to distinguish permissions and profiles as well as a remedy for duplicate names. If not taken care of carefully, users authenticated through a 3rd party LDAP will follow LDAP naming conventions, which is a PITA. When
In any case, it is transparent for an application developer on Domino how a user authenticates, you only need to care that it is happening when you protect a resource. Keep in mind: authentication is only secure via https!
It doesn't matter what access a user might have inside a database, if the server won't let the user access its resources. So having your admin locking down the server properly is your first line of defense. Server access is defined in the server document that also contains the ECL for the server. A normal user doesn't need ECL permissions, only the ID that is associated with the XPage (or agent) that a user wants to run. "Associated" here means: the ID the code was signed with. By default every time a developer saves an XPage, that page gets signed with the developer's ID. This is very different from file based application servers where a file doesn't contain a signature, but similar to the JAR signing in the Java world. Keep in mind: in Java that is a manual process using a command line tool and requires the acquisition of an (expensive) code signing certificate, while in Domino it is automatic.
Common practise however is, not to allow a developer to run code on a production server (unless you are Paul), but signing the database with either the server.id or a specific signer ID. This step would be performed by your admin.
When you access an NSF, the access level is set in the ACL to one of these values: No Access, Depositor, Reader, Author, Editor, Designer, Manager.
Additionally a user can have roles assigned to her, that allow a refinement of interaction and access. Roles are always used with the name in square brackets. Typical roles are [server] or [Admin]. Roles are defined per NSF. The following tables shows the permitted operations per access level:
Having read access to a database doesn't automatically make all documents visible. They still can be protected by reader fields. More below
Having Author access to the database does enable a user to edit any document where the user is listed in one or more items of type author, While Editor access allows to edit any document the user can see. So as a rule of thumb:
The access level for normal users to a Notes/Domino based application should be set to Author
Looking at the above table you could conclude: Author fields are only relevant for users with exactly Author access to a database: if the access is lower they won't be able to edit anything, if the access is higher, they can edit anything. However in conjunction with Reader fields they have a second purpose. Reader protection is defined as:
When a document has at least one item of type Readers that has content (non-empty), then access to that document is restricted to users and servers that are explicitly (by name) or implicitly (by group membership, role or wildcard) listed in any of the Reader or Author items.
A typical pattern in a Notes application would be a computed Author field with the value
A popular mechanism is to provide a checkbox "Confidential" and then compute a reader field:
Domino applications are protected by a hirarchical control system. If you fail to pass one hierachy level's test, it doesn't matter if a lower level would be compatible to you current credentials. E.g. when a database would allow anonymous access, but the server is configured to require authentication, you must authenticate. To fully understand the options, sit back and recall the difference between authentication and authorization. The former establishes who you are, the later what you can do. Let's look at both parts:
Authentication
When using a Notes client (including XPiNC) or running a Domino server, the identity is established using a public-private key challenge. The key is stored in the Notes.id file and (usually) protected by a password. So it qualifies as a 2 factor authentication (you need something, you know something). The beauty of this PKI approach is the availability of keys for signatures and encryption. Since users hate password entries you can perform unlocking of the Notes.id using various methods for single signon.Accessing Domino through http(s) (or SMTP, IMAP and POP) uses open standards based authentication. I will focus on the http(s) options here. When a resource is protected (more on that later) the user is presented with an authentication challenge. In its simplest form it is http BASIC authentication that prompts for a username and password. In web UIs this isn't en vogue anymore, but in REST based access pulling and pushing JSON or XML it is still quite popular, since it is simple to use.
The most prevalent form (pun intended) is form based authentication. If a protected resource requires higher access than the current known user (who is anonymous before logging in), the user is redirected to a login page, where username and password are requested. This authentication can be per server or for a group of servers using LTPA or 3rd party plug-ins.
Users typically are listed in the Domino Directory or any compatible LDAP directory configured as authentication source. Users on Domino mail need to be in the Domino directory for mail routing to work.
A typical (structural) mistake: trying to use a remote 3rd party LDAP which creates additional network latency and single point of failure (the remote LDAP). When your Domino application server is running, your directory service is available, I wouldn't step away from this robustness. If your users strategically are maintained in a more fragile directory, use TDI to keep them in sync.
The final option to authenticate users is the use of X509 certificates. This requires the public X509 key to reside in the directory and the private key in the user's browser. I haven't seen that in large rollouts since it is a pain to administrate.
Anyway, as a result of an authentication, a user is identified with an X500 compatible name:
CN=Firstname LastName/OU=OrgUnit4/OU=OrgUnit3/OU=OrgUnit2/OU=OrgUnit1/O=Organisation/C=Country
Country (/C) and the Organisation Units (/OU) are optional. Typically we see 1-2 OrgUnits in use. They are practical to distinguish permissions and profiles as well as a remedy for duplicate names. If not taken care of carefully, users authenticated through a 3rd party LDAP will follow LDAP naming conventions, which is a PITA. When
@UserName()
doesn't start with CN= (unless it returns Anonymous) you need to take your admins to task.
In any case, it is transparent for an application developer on Domino how a user authenticates, you only need to care that it is happening when you protect a resource. Keep in mind: authentication is only secure via https!
Authorisation
Now you know who the user is, you define what (s)he can do. Domino uses 2 mechanism: the Access Control List (ACL) to define read/write access levels and the Execution Control List (ECL) to define what code a user can run. The first level of authorization is server access:It doesn't matter what access a user might have inside a database, if the server won't let the user access its resources. So having your admin locking down the server properly is your first line of defense. Server access is defined in the server document that also contains the ECL for the server. A normal user doesn't need ECL permissions, only the ID that is associated with the XPage (or agent) that a user wants to run. "Associated" here means: the ID the code was signed with. By default every time a developer saves an XPage, that page gets signed with the developer's ID. This is very different from file based application servers where a file doesn't contain a signature, but similar to the JAR signing in the Java world. Keep in mind: in Java that is a manual process using a command line tool and requires the acquisition of an (expensive) code signing certificate, while in Domino it is automatic.
Common practise however is, not to allow a developer to run code on a production server (unless you are Paul), but signing the database with either the server.id or a specific signer ID. This step would be performed by your admin.
When you access an NSF, the access level is set in the ACL to one of these values: No Access, Depositor, Reader, Author, Editor, Designer, Manager.
Additionally a user can have roles assigned to her, that allow a refinement of interaction and access. Roles are always used with the name in square brackets. Typical roles are [server] or [Admin]. Roles are defined per NSF. The following tables shows the permitted operations per access level:
Read Access
Having read access to a database doesn't automatically make all documents visible. They still can be protected by reader fields. More below
Write Access
Having Author access to the database does enable a user to edit any document where the user is listed in one or more items of type author, While Editor access allows to edit any document the user can see. So as a rule of thumb:
The access level for normal users to a Notes/Domino based application should be set to Author
Reader & Author fields
They are quite unique to Domino, since they allow declarative protection of a note. If you implement (in code) something similar in an RDBMS, you get quite a complex relation:Looking at the above table you could conclude: Author fields are only relevant for users with exactly Author access to a database: if the access is lower they won't be able to edit anything, if the access is higher, they can edit anything. However in conjunction with Reader fields they have a second purpose. Reader protection is defined as:
When a document has at least one item of type Readers that has content (non-empty), then access to that document is restricted to users and servers that are explicitly (by name) or implicitly (by group membership, role or wildcard) listed in any of the Reader or Author items.
A typical pattern in a Notes application would be a computed Author field with the value
[server]
. The application server would get the role in the ACL. Since a server most likely has Manager access anyhow, it has initially no impact on the application. However when some mechanism activates reader protection, this field ensures that the server can see all documents. It is important to use an Author field/item here, to avoid triggering read protection where it isn't necessary. Reader fields have a performance cost, so use them wisely.
A popular mechanism is to provide a checkbox "Confidential" and then compute a reader field:
@if(Confidential!="";DocumentPeople;"")
, where "DocumentPeople" would be an item of type Names. In workflow applications, the content of reader and author fields isn't static, but changes with the progress of the workflow. Careful planning is required.
There is more
Notes can refine access further. Documents can be encrypted and signed, as well as sections in a document can be access controlled or signed. However those capabilities are not yet exposed to the XPages API and are thus of limited interest for new XPages developers.Further readings
There are a number of related articles I wrote over the years:- Access Control in Domino - the Basics
- Access control in Domino - Part 2: Inside your NSF
- Protect your Domino applications from Firesheep
- Workflow and Document Access
- Access protected Notes documents - RDBMS style
- NoReader and NoAuthor Fields
- Reader fields (again) - discussed performance impacts and mitigation
- Reader Fields - extreme Edition (update)
- Reader fields for large user populations (Extreme Edition 2.0)
Posted by Stephan H Wissel on 04 February 2014 | Comments (0) | categories: IBM Notes XPages


Chapter 6. All About Access Controls
Access controls are the most important part of your Squid
configuration file. You'll use them to grant access
to your authorized users and to keep out the bad guys. You can use
them to restrict, or prevent access to, certain material; to control
request rewriting; to route requests through a hierarchy; and to
support different qualities of service.
Access controls are built from two different components. First, you
define a number of access control list (ACL)
elements.
These elements refer to specific aspects of client requests, such as
IP addresses, URL hostnames, request methods, and origin server port
numbers. After defining the necessary elements, you combine them into
a number of access list rules. The rules apply to particular services
or operations within Squid. For example, the
http_access rules are applied to incoming HTTP
requests. I cover the access control elements first, and then the
rules later in this chapter.
|


Version Control, Git and GitHub - Your New Best Friends
You can't have a beer with them, but they've got your back
March 20th 2015
Version control could very well be your best friend. He keeps tabs on you often, making sure to back you up when you fall down. He encourages you to try new things, and lets you know that there is always a fallback if the new 'thing' doesn't work out. Version control with git is a truly incredible system. Version control allows you to continually work on a project and create snapshots in time as you add new additions to your project. Just like a checkpoint in a game, you know you can always revert to that checkpoint if you fail. Version control with git allows you to create checkpoints for your code however often you would like. How cool is that? Accidentally delete a block of code? Git can revert to the most recent checkpoint with the code. Accidentally introduce a bug? Git can help you go back to a time when the bug was nonexistant.
In order for version control and git to become your best friendS, you must be a good friend to them. What does this mean? You must 'ping' git often to save a historical snapshot of new work you have created!How do you do this? With a 'git commit'! As you continue to make additions and updates to your code, you must package those changes into a git commit.  When you are happy with the code - you can stage the changes. After staging the changes, you can 'commit' the changes. The key here is that you must put a message with each commit describing what code you have modified. If the commit looks good to you, you can create a pull request and ask a team member to review your code and merge it to the master or you can merge it yourself! It's just that simple. Just remember to commit often!
Now what if you are working on a project with others? GitHub has your back! GitHub is a remote repository where you can store projects. You can have team members all access the same code base, and make modifications to it on their local machine. The huge benefit of this is that each team member can be working on the project remotely at the same time - then merge in his or her code changes to the master code repo. This avoids team members working on a number of different versions. As you make your unique changes and merge them to the master branch, your team members are able to pull in those changes to their machine without impacting any changes they might be working on. GitHub allows you to work remotely as a team on the same project without stepping on eachother's toes.
WOOHOO!


hydroscoper
provides an R interface to the Greek
National Data Bank for Hydrological and Meteorological Information
http://www.hydroscope.gr/.
hydroscoper
covers Hydroscope's data sources using the
Enhydris API and provides functions to:
Transform the available tables and data sets into tibbles.
Transliterate the Greek Unicode names to Latin.
Translate various Greek terms to English.
The Enhydris database is implemented in PostgreSQL. Details about the database can be found here and about the Web-service API here.
The data are retrieved from the Hydroscope's databases:
Ministry of Environment, Energy and Climate Change.
Ministry of Rural Development and Food.
National Meteorological Service.
Greek Public Power Corporation.
Useful links:


Welcome!
My name is Aditya Tanjore, and I study economics, political science, and business institutions at Northwestern University. My interests lie in the investigation of interstate conflicts around the globe and understanding the economics linked to the emergence of right-wing populist sentiments, as well as in leadership development in business and beyond. Please feel free to read through my bio, peruse through my work and thoughts, or ask me a question!
-
Hello!
As a native of Chicago, I am more than thrilled to be attending Northwestern University for my undergraduate studies! After growing up in the north suburbs of Chicago for 13 years, I moved to Frankfurt, Germany to complete high school.
While living in Frankfurt, I developed my interest in the emergence of conflicts, as well as in understanding the development of right-wing populist sentiments. As I began to witness the effects of both of these firsthand in my own community, as Frankfurt and many other German cities began accepting refugees from Syria and other regions experiencing civil conflict, I became extremely interested in studying these topics in greater detail.
Since having lived abroad, I have actively begun to explore my interest in the policy implications associated with accepting individuals affected by intrastate conflicts, as well as in leadership development in the business environment through my coursework and extracurricular experiences here at Northwestern. I have especially sought experiences that develop my own personal leadership style in co-founding Lambda Strategy, Northwestern's first strategy consulting group that staffs project teams with both undergraduates and Kellogg MBA candidates, for small- to medium- sized clients operating in the private sector.
In addition to co-founding Lambda, I have also become very interested in pursuing a career in management consulting, and have become particularly focused on the culture and atmosphere related to recruitment in this industry, especially on Northwestern's campus.
-
My current interests lie in the following:
- Understanding the causes and comparative analyses of civil conflicts around the world
- Working with students to help them make the most out of their Northwestern experience
- Addressing pre-professional / business culture at Northwestern
- Developing useful techniques in navigating through on-campus consulting recruitment
- Engaging in oppurtunities for personal and professional growth, both within and beyond the classroom
- Exploring potential oppurtunities in strategy consulting project work for Lambda Strategy
-
Throughout my time at Northwestern, as well as after I graduate, I would like to be able to:
- Engage with others' varying opinions on the emergence and effects of civil conflicts
- Create an open platform for individuals to discuss their expereinces and questions related to Northwestern
- Impart any advice related to guiding oneself through their time at Northwestern that I have found useful for myself
- Work towards addressing and combating the often-exclusive nature of pre-professional and business environments on campus
- Develop and build onto my own personal leadership style


Being a physicist by training gives me the ability to work with general concepts and models, using physics, math and the scientific method to solve problems.
Becoming a software engineer by need gives me the experience to work with programming and computer architecture in a practical way, using performance, easy of use and generality as guiding principles.
Turning into a data scientist by choice is something that allows me to find intelligent solutions with all above on real problems and solutions.
And being an optimist, I believe that I can do stuff while still having some fun!
I have experience in Telecom, Agriculture and Environment problems, applying Machine Learning, Statistics, Big Data and the good old Scientific Method.
You can reach me at ispmarin@gmail.com.


{% extends "base.html" %} {% block page_title %}How it Works{% endblock %} {% block content %}
The goal of demoQRacy is to make offline voting easier. For example, pretend you're hosting a bake off, where five bakers will compete to make the best brownies in town. Your judges will be fifty people in attendance. Using demoQRacy, you can print out a large, unique barcode for each baker's table. After your judges have tried all the brownies, they scan the barcode using their mobile phones, which registers their vote. Vote counts are visible only to you, through this website.
Voters identify themselves using their Google Accounts: the same usernames they use to access Google services like Gmail, Google Docs & Spreadsheets, YouTube, and more. Many users will already have a Google Account, and those that don't will see an easy signup form. All votes are stored anonymously, but each user may only vote once per election.
{% endblock content %}


---
layout: post
title: Is Obama's Lead In Gallup Polls Stable Or Volatile?
date: '2008-08-05T23:12:36-07:00'
tags:
tumblr_url: http://alexhwilliams.tumblr.com/post/44899851/is-obamas-lead-in-gallup-polls-stable-or-volatile
---
Is Obama's Lead In Gallup Polls Stable Or Volatile?
Look at the polls over a 10-day period and the numbers show Obama with a consistent three to four point lead. Lesson: The noise? It’s an optical illusion.


Search Inside Yourself: Musings on Chapter One
So far I've been enjoying the book, though I find the author does a lot of qualifying before he goes the discussion. It made me think that he thinks his audience is a bunch of people who don't actually want to be reading his book! Maybe he's right...
Another reflection has been that it's quite confronting for me to read about mindfulness and meditation in the context of making money and progressing your career. Sentences like the following:
"...in other words, what if contemplative practices can be made beneficial both to people's careers and to business bottom lines?"
"I hope your journey will be fun and profitable"
It's interesting because I have always thought of mindfulness as one of many practices and tools that could help (for want of a better word) revolutionise the world and facilitate a shift towards a more thriving planet. To me, profit and business bottom lines are not compatible with this, so it's a little jarring to hear someone talk about such things in the context of mindfulness and meditation.
Despite this, I can empathise with his attempt to de-hippify the practise, and I appreciate this. Tan is coming from a good place, his wrting is easy and pleasant to read, I'm looking forward to reading more from him.
My two minutes of mindfulness were nice and relaxing. I really enjoy meditation, but even after years of trying I still find it very difficult to keep up a regular practice. I appreciate how bite-sized Tan makes it seem. I'm finding that to be quite a theme over the last month or so, breaking stuff into bite-sized bits. So far it's really helping in other areas of my life so I think that this approach to mindfulness will be really valuable.


Table Name: tabUser
| Sr | Fieldname | Type | Label | Options |
|---|---|---|---|---|
| 1 | sb0_5 |
Section Break | ||
| 2 | enabled |
Check | Enabled | |
| 3 | section_break_3 |
Section Break | ||
| 4 | email |
Data |
|
|
| 5 | first_name |
Data | First Name | |
| 6 | middle_name |
Data | Middle Name (Optional) | |
| 7 | last_name |
Data | Last Name | |
| 8 | username |
Data | Username | |
| 9 | send_welcome_email |
Check | Send Welcome Email | |
| 10 | unsubscribed |
Check | Unsubscribed | |
| 11 | column_break0 |
Column Break | ||
| 12 | language |
Select | Language |
Loading... |
| 13 | time_zone |
Select | Timezone | |
| 14 | user_image |
Attach Image |
User Image
Get your globally recognized avatar from Gravatar.com |
|
| 15 | short_bio |
Section Break | More Information | |
| 16 | gender |
Select | Gender |
Male Female Other |
| 17 | birth_date |
Date | Birth Date | |
| 18 | location |
Data | Location | |
| 19 | column_break_22 |
Column Break | ||
| 20 | bio |
Small Text | Bio | |
| 21 | mute_sounds |
Check | Mute Sounds | |
| 22 | change_password |
Section Break | Change Password | |
| 23 | new_password |
Password | Set New Password | |
| 24 | send_password_update_notification |
Check | Send Password Update Notification | |
| 25 | reset_password_key |
Data | Reset Password Key | |
| 26 | email_settings |
Section Break | Email Settings | |
| 27 | thread_notify |
Check | Send Notifications for Transactions I Follow | |
| 28 | email_signature |
Small Text | Email Signature | |
| 29 | background |
Section Break | Desktop Background | |
| 30 | background_image |
Attach | Background Image | |
| 31 | background_style |
Select | Background Style |
Fill Screen Tile |
| 32 | sb1 |
Section Break |
Roles
Check / Uncheck roles assigned to the User. Click on the Role to find out what permissions that Role has. |
|
| 33 | roles_html |
HTML | Roles HTML | |
| 34 | user_roles |
Table | Roles Assigned | UserRole |
| 35 | modules_access |
Section Break |
Modules Access
Uncheck modules to hide from user's desktop |
|
| 36 | modules_html |
HTML | Modules HTML | |
| 37 | block_modules |
Table | Block Modules | Block Module |
| 38 | sb2 |
Section Break |
Defaults
These values will be automatically updated in transactions and also will be useful to restrict permissions for this user on transactions containing these values. |
|
| 39 | defaults |
Table |
User Defaults
Enter default value fields (keys) and values. If you add multiple values for a field, the first one will be picked. These defaults are also used to set "match" permission rules. To see list of fields, go to "Customize Form". |
DefaultValue |
| 40 | sb3 |
Section Break | Security Settings | |
| 41 | user_type |
Select |
User Type
User Type "System User" can access Desktop. "Website User" can only be logged into the website and portal pages. |
System User Website User |
| 42 | login_after |
Int |
Login After
Allow user to login only after this hour (0-24) |
|
| 43 | login_before |
Int |
Login Before
Allow user to login only before this hour (0-24) |
|
| 44 | restrict_ip |
Data |
Restrict IP
Restrict user from this IP address only. Multiple IP addresses can be added by separating with commas. Also accepts partial IP addresses like (111.111.111) |
|
| 45 | column_break1 |
Column Break | ||
| 46 | last_login |
Read Only | Last Login | |
| 47 | last_ip |
Read Only | Last IP | |
| 48 | last_active |
Datetime | Last Active | |
| 49 | last_known_versions |
Text |
Last Known Versions
Stores the JSON of last known versions of various installed apps. It is used to show release notes. |
|
| 50 | third_party_authentication |
Section Break | Third Party Authentication | |
| 51 | fb_username |
Data | Facebook Username | |
| 52 | fb_userid |
Data | Facebook User ID | |
| 53 | google_userid |
Data | Google User ID | |
| 54 | column_break_49 |
Column Break | ||
| 55 | github_userid |
Data | Github User ID | |
| 56 | github_username |
Data | Github Username |
Inherits from frappe.model.document.Document
a_system_manager_should_exist (self)
No docs
Add roles to user and save
add_system_manager_role (self)
No docs
after_rename (self, olddn, newdn, merge=False)
No docs
Add roles to user
set name as email id
before_rename (self, olddn, newdn, merge=False)
No docs
No docs
email_new_password (self, new_password=None)
No docs
No docs
get firstname space lastname
get_other_system_managers (self)
No docs
No docs
No docs
password_reset_mail (self, link)
No docs
password_update_mail (self, password)
No docs
remove_all_roles_for_guest (self)
No docs
No docs
No docs
send_login_mail (self, subject, template, add_args)
send mail with login details
send_password_notification (self, new_password)
No docs
send_welcome_mail_to_user (self)
No docs
No docs
No docs
No docs
username_exists (self, username=None)
No docs
No docs
validate_email_type (self, email)
No docs
validate_rename (self, olddn, newdn)
No docs
validate_share (self, docshare)
No docs
validate_system_manager_user_type (self)
No docs
No docs
frappe.core.doctype.user.user.extract_mentions (txt)
Find all instances of @username in the string. The mentions will be separated by non-word characters or may appear at the start of the string
frappe.core.doctype.user.user.get_active_users ()
Returns No. of system users who logged in, in the last 3 days
frappe.core.doctype.user.user.get_active_website_users ()
Returns No. of website users who logged in, in the last 3 days
Public API
/api/method/frappe.core.doctype.user.user.get_all_roles
frappe.core.doctype.user.user.get_all_roles (arg=None)
return all roles
Public API
/api/method/frappe.core.doctype.user.user.get_languages
frappe.core.doctype.user.user.get_languages ()
No docs
Public API
/api/method/frappe.core.doctype.user.user.get_perm_info
frappe.core.doctype.user.user.get_perm_info (arg=None)
get permission info
frappe.core.doctype.user.user.get_permission_query_conditions (user)
No docs
frappe.core.doctype.user.user.get_system_users (exclude_users=None)
No docs
frappe.core.doctype.user.user.get_total_users (exclude_users=None)
Returns total no. of system users
Public API
/api/method/frappe.core.doctype.user.user.get_user_roles
frappe.core.doctype.user.user.get_user_roles (arg=None)
get roles for a user
frappe.core.doctype.user.user.get_website_users ()
Returns total no. of website users
frappe.core.doctype.user.user.has_permission (doc, user)
No docs
frappe.core.doctype.user.user.notifify_admin_access_to_system_manager (login_manager=None)
No docs
Public API
/api/method/frappe.core.doctype.user.user.reset_password
frappe.core.doctype.user.user.reset_password (user)
No docs
Public API
/api/method/frappe.core.doctype.user.user.sign_up
frappe.core.doctype.user.user.sign_up (email, full_name)
No docs
Public API
/api/method/frappe.core.doctype.user.user.update_password
frappe.core.doctype.user.user.update_password (new_password, key=None, old_password=None)
No docs
frappe.core.doctype.user.user.user_query (doctype, txt, searchfield, start, page_len, filters)
No docs
Public API
/api/method/frappe.core.doctype.user.user.verify_password
frappe.core.doctype.user.user.verify_password (password)
No docs


This weekend past, myself and several friends decided to go to Nitnat lake camping. This is a fairly secluded lake on Vancouver Island in British Columbia. I had purchased some mushroom chocolates about a week before thinking to take them that weekend. The lake was an excellent place to experience a psychedelic experience, clear skies, warm weather, very few negative vibes, untamed wilderness, wind surfers on the lake. I took my chocolates at about 1615, deep down inside I was slightly sketched that they were not going to work.
However, after about 15 minutes when the first pangs of nausea and that feeling of limbo began to strike, I felt a huge relief and euphoria, they were going to work. As I lay in the sun watching the trees and sand I began to feel the effects more profoundly. My first inkling that something very good was up was when I looked at a wine bottle and was shocked to discover that it had somehow become crooked, I looked around and the bottles that surrounded me were all in a similar state of morphing.
45 minutes after first taking them I rolled over onto my stomach and momentarily closed my eyes. I was rather surprised to notice a series of flashing lights disappearing towards a point slightly to the left of the center of my vision. I kept my eyes closed wanting to see more of this. The more I concentrated the vision changed, becoming a pattern similar to that of a leafs underside. The area between each of the veins upon closer inspection seemed to each be a portal to a different vision. I focused first on one with a man standing in the desert, then another of swirling lights.
My focus on the leaf was interrupted by a vision of what appeared to be an angel in the upper right of my visual field. This angel was drawn in the style on the medieval artists, leading me to the thought that perhaps the artists of that time were not just bad at drawing, but had actually seen the same thing as me and were merely recording their trip and contact with what they believed to be angels.
After watching this bizarre spectacle for some time I became aware of a human face occupying the center of my vision, it was a beautiful girl, about 20 years old, with long dark hair, I seemed I was seeing her through a heavily leaded plate glass window, the cracks between the panes of this glass actually turned out to be holes into a far deeper field, as I peered through them I was aware of dazzling lights and flashing stars moving down towards me.
I became aware that I was beginning to get sun burnt and decided to move to another place. Much to my surprise, the strong visuals did not stop when I opened my eyes but merely became embossed on everything I was seeing. They lost their colouring and it appeared as if the world had become 2 dimensional and these visions imprinted onto it. I wandered around the beach, amazed at the experience of exploring a 2 dimensional world. Finally I decided to go to my tent to see what that would be like. Lying on my side I began to notice colourful patterns of arrows sliding back and forth along the mesh in the ceiling. I lay there for about half an hour transfixed by their amazing dance.
Finally I realized that it was time for dinner so walked down the beach amid a series of dancing stars and flashes. At this point I had become used to the concept that I was going to be seeing some very strange things tonight and none of this phased me. Upon arrival at my car I discovered that it had miraculously turned purple (it is usually a hideous brown) and like every other car appeared to be glowing. As dinner cooked I was able to have a fairly intelligent conversation with my fellow campers (all stuck on earth) and became aware that the visual effects were wearing off. It had been 4 hours since I ingested the chocolates. Gone were the vivid hallucinations, replaced with the odd effect that everything was surrounded by a halo of light.
After dinner we walked through the forest, my visuals were all but gone and had been replaced by a feeling of enormous euphoria and excitement. I was also thinking on a level far clearer than ever before, my mind seemed to be free of the usual encumbrances of personal issues and I was able to appreciate the universe and our tiny part in it. Walking back down the river the beauty of the world over took me and I stood transfixed by an enormous tree, doing a monologue about the how infinitesimally small man actually is in the universe. Upon returning to camp I felt entirely normal except for being exceptionally happy, and philosophical. That night it took a long time to fall asleep because of the huge thoughts that seemed to be playing across my mind. The next morning found me with no ill effects, simply a better understanding of how tiny we are and how beautiful the world is.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


What's New
New Changes that will be coming to RateMyCourse
RateMyCourse Beta has been created and the main function so far done is allowing students to let students see which courses would be best for them based on filters created so far which is enjoyment of the class, diffuctly, overall experience, and grade recieved.


What a day. First Nokia bought Plazes (Congrats!) and now they offer to buy the remaining 52% of Symbian and have launched the Symbian Foundation, which will drive the open sourcing of Symbian over the next 2 years. Of course the Symbian Foundation has wide adoption, same as the Open Handset Alliance around Android, but we might want to dig a bit deeper to see if this is a lost cause by Nokia as Google will simply win with Android, or not.

First to start of with one thing. Nokia sells as many phones in a few days as Apple has sold iPhones in total. So there is a bit of a market power there. Of course, Apple might be able to scale down, and Android might be nice, but there is power behind the Symbian Foundation, real power.

Another question is who is now building mobile phones. Nokia, Sony Ericsson, Samsung, Lg, Ericsson, Motorola … all members of Symbian and many of them missing from Google’s Alliance. One also has to say that these companies have real relations to carriers and real experience to get phones through testing with the FCC and others.

Also, Google lists China Mobile as part of the Open Handset Alliance, but they seem to have problems getting chinese working on Android, and Chinese does work on Symbian obviously, and with Open Sourcing the platform, there are no longer any real licensing fees and China Mobile might have an easier access route with Symbian to get their own Smartphones.

So yes, Nokia needs to build up their developer relations work to get some serious buzz around new apps for Symbian, but this is something that can be done because it is a really good base. I still want an iPhone but I will keep my N95 and I will likely get a Nokia phone again in the future.  It has the buzz factor at the moment. Android is too far away. And possibly Nokia will have some really compelling items out at the end of the year. And hey, just imagine them adding Plazes to a few of their phones. Give it a month and there will be more Plazes installations on phones than iPhones out there. So long Loopt. Nice to have met you.


AUSTIN POWERS: THE SPY WHO SHAGGED ME (New Line) Starring: Mike Myers, Heather Graham, Robert Wagner, Michael York, Mindy Sterling, Seth Greene, Verne Troyer, Rob Lowe. Screenplay: Mike Myers & Michael McCullers. Producers: Suzanne Todd, Jennifer Todd, Demi Moore & Eric McLeod and Mike Myers & John Lyons. Director: Jay Roach. MPAA Rating: PG-13 (profanity, adult themes, adult humor) Running Time: 95 minutes. Reviewed by Scott Renshaw.
First, this must be said: I was wrong about the original AUSTIN POWERS: INTERNATIONAL MAN OF MYSTERY. In 1997, I gave the film an unenthusiastic 5 out of 10, noting that writer/star Mike Myers' infatuation with old "Saturday Night Live" sketches and characters blunted the truly inspired comic moments. I'm still pretty comfortable with my rating, though a recent second viewing suggested I may have been slightly stingy (Dr. Evil alone is too hilarious not to warrant at least a mild recommendation). No, I was wrong in a suggestion I made for improvement. I thought AUSTIN POWERS might have worked better as a pure 1960s period piece rather than a fish-out-of-water comedy with shagadelic, cryogenic secret agent Austin Powers (Myers) coping with 1990s life when he's thawed out to battle old nemesis Dr. Evil (also Myers). AUSTIN POWERS: THE SPY WHO SHAGGED ME proves that a different temporal setting wouldn't have changed anything, because Myers used a different temporal setting and _didn't_ change anything.
Those familiar with the original -- mostly from its spectacular second life on video -- will recall that we left Dr. Evil drifting through space in his Big Boy rocket while Austin honeymooned with agent Vanessa Kensington (Elizabeth Hurley). Both the Big Boy and Vanessa are quickly dispatched to set Dr. Evil on his latest plan, which requires getting Austin out of the way. His fiendish plot involves traveling back through time to 1969 to steal from the still-frozen Austin the source of all his Powers: his mojo. Faster than you can say Basil Exposition (Michael York), Austin has a time machine of his own, and pops back to swinging London. There he teams up with CIA operative Felicity Shagwell (Heather Graham) to recapture the mojo in question and prevent something evil from happening.
The exact nature of that something evil is, of course, entirely beside the point. THE SPY WHO SHAGGED ME is at its goofy best when it's most self-aware, mocking film conventions of all sorts. Austin and Felicity drive through the "English Countryside" while noting "it's amazing how much England looks in no way like Southern California;" concerns about physics of time travel are dismissed with an admonishment to the audience to do the same. Myers can be utterly brilliant working with incongruous situations, as when he follows a romantic liaison between Dr. Evil and co-worker-in-evil Frau Farbissina (Mindy Sterling) with an awkward "morning after" meeting at the underground lair's coffee machine. When Myers finds a comic target -- Starbucks, the music of the 80s, STAR WARS' opening narrative crawl -- he knows how to use it.
He also doesn't know how to _stop_ using it. The original AUSTIN POWERS was at its most wearying when Myers took a joke and beat all semblance of life out of it for several agonizing minutes. He's at it again this time, and he's using identical gags he already exhausted in the previous film. Once again, a naked Austin's naughty bits are hidden strategically by other (usually phallic) objects; once again, Dr. Evil engages in a binge of pre-emptively shushing his son Scott (Seth Greene); once again, Austin makes several exaggerated, James Bond-like puns referring to a villain's demise. Even the original's best sequence -- the Evil family therapy session -- is revisited as a "Jerry Springer" episode. And when Myers does come up with a new concept, he still insists on using it twice, or twice as long as necessary. We've all come to expect sequels that recycle huge chunks of the original, usually in the action genre. When a satirical comedy loses its sense of discovery, there's not much reason for it to exist.
The one major change is the 1969 setting, though there doesn't seem to be much point to it. The best reason for putting Austin back in his element is to watch him be his lascivious, un-self-conscious self through contemporary eyes. Unfortunately, the plot turns him into a mojo-impaired 90s guy worried about his relationship, leaving the setting-specific humor to a few Dr. Evil anachronisms. There are some other new twists -- the diminutive Dr. Evil clone Mini-Me (Verne Troyer); Rob Lowe doing a dead-on Robert Wagner impression as the young Number 2; Myers finding a way to do another character _and_ work in his beloved Scottish accent as the grossly obese, aptly named Fat Bastard -- that hit and miss. Mostly, it's a lot more of the same. That's a good thing when we're talking about Dr. Evil, still looking for super-villain respect while dealing with a complicated personal life. That's a bad thing when we're talking about making the same mistakes twice. AUSTIN POWERS fans will surely be ready to forgive Myers' lapses in imagination. Others will be left trying to figure out where this promising series could actually reach its potential. Maybe the 1950s next time?
On the Renshaw scale of 0 to 10 Powers urges: 5.
Visit Scott Renshaw's Screening Room http://www.inconnect.com/~renshaw/ *** Subscribe to receive new reviews directly by email! See the Screening Room for details, or reply to this message with subject "Subscribe".
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


CimCoin
create transaction
miner
view chain
my transactions
Cim Coin
Cim lab's cryptocurrency!
new transaction
sender
recipient
amount
Submit


Build Early Ed strengthens the continuum of care for youth by connecting New Mexicans to Head Start programs. We help New Mexicans enroll their children into Head Start, earn higher education credentials, and connect with local advocates to build Head Start programs in their community. Together, we can build the future of early childhood education.


We now extract the compiled .scss to its own .css file in the /dist folder
We do need a link in the header of the document
we used mini-css-webpack-plugin for this
See the `webpack.config.js` file for a demonstration of using and configuring the plugin.
Don't forget to `npm install` the needed loaders first!
More options can be found at https://webpack.js.org/plugins/mini-css-extract-plugin/


Quick Start
Introduction¶
What follows is a detailed tutorial that walks developers through all of the steps involved in creating a customizable iOS or tvOS application using P2UX. Developers should be familiar with the Xcode integrated development environment for MacOS and either the Swift or the Objective-C programming languages for custom coding.
Terminology
Throughout the P2UX documentation the “developer” refers to you, the reader who is developing an app with P2UX. The “designer” refers to the individual whose principal job is to create the appearance and style of the app and its visual components. “PRL” refers to the P2UX Rendering Library for iOS, which controls the creation and workflow of content created for the P2UX platform.
Coding examples and code additions
In the coding examples below and throughout the documentation, changes and additions to be made by the developer are rendered with a blue highlight.
P2UX versus the standard Xcode environment
P2UX based applications for iOS are easy to customize and extend. Since the P2UX iOS rendering library is based on the native UIKit and other iOS primitives, writing custom business logic and integrating custom controls works much the same as it does when writing iOS applications using Xcode. With the P2UX platform, Storyboards and XIB based User Interface (UI) definitions are no longer required. Instead, applications use P2UX Portable UX Bundles (PUB) either as embedded or dynamically accessed resources. Additionally, P2UX provides hooks to developers that allow them access to all of the components of P2UX, as well as the ability to fully customize instances of the application.
Getting Started with P2UX and Xcode¶
Objective-C or Swift
P2UX native rendering libraries for iOS can be extended using either Objective-C or Swift. Developers are free to choose one or the other of these coding languages at any stage during the development process. The instructions below provide explicit reference to the proper use of either language in each applicable step that follows.
Creating a new application¶
From the Xcode environment:
- Start the Xcode new project wizard by selecting File->New->Project.
- From the new project wizard select “Single View Application” as the starting point for your app.
- The rest of the options in the new project wizard are dependent on your application and the selection of either Swift or Objective-C.
Connecting the PUB. Defining assets and custom behaviors¶
Now that the initial project is set up, make the necessary changes to include the PUB for the application.
- Remove the Storyboard
When Xcode creates a new project, it automatically generates a blank storyboard file called Main.storyboard
. Rather than using storyboards to create the UI for your app, your app will use a PUB. To accomplish this, simply remove the Main.storyboard
file from your project.
First, delete the file itself from your project (move to trash).
Next, in Info.plist
, remove the key Main storyboard file base name.
- Select the Info.plist file from the project navigator.
- From the editor on the right side, select the Main storyboard file base name row.
- Double click on the word Main from that row to edit it and delete the text, leaving the Value field empty.
- Save the modified
Info.plist
file.
Finally, in the project navigator under “Deployment Info,” delete the text from “Main Interface” so that the text field is blank.
- Select the application name from the project navigator.
- From the right side editor, select the application target.
- Select the General tab (shown highlighted in blue in the example screenshot)
- In the section titled Deployment Info, select the text in the Main Interface field and delete the text, leaving the field empty.
- Save the project changes. Now, your app runs without a storyboard.
Enabling P2UX iOS Frameworks¶
The next step in developing your project with P2UX is to include the P2UX frameworks for iOS. The latest frameworks can be downloaded from this site (INSERT URL ONCE AVAILABLE). Once the frameworks are downloaded:
- Unzip the framework files.
- Copy the P2UXCore.framework, P2UXApp.framework and postbuild.sh files into the root of your project directory.
- Add the framework files to your project in Xcode.
- Select your project in the project navigator on the left side and then click on the Target for your project.
- Select the General tab in your project target settings.
- In the section labeled Embedded Binaries, click the + button, then click the Add Other… button from the drop down dialog.
- Find the two framework files you added to your project folder, select them and then click Open.
- Add
postbuild.sh
as a Build Phases script.- Select your project in the project navigator on the left side and then click on the Target for your project.
- Select the Build Phases tab for your project.
- Click the + button in the Build Phases window to add a new build step and select New Run Script Phase from the drop down menu
- In the new Run Script phase, click in the shell script area and paste in the text ./postbuild.sh. This assumes you copied the
postbuild.sh
file from the earlier step into the root of your project.
Removing unused binaries by running the postbuild.sh
script
The step above removes unused binaries from the P2UX frameworks for the current architecture. By default, P2UX frameworks are built as fat binaries, that is, they have compiled support (binaries) for actual iOS devices and for mac-based simulators all in the same framework bundle. This means that both Xcode simulators and real iOS devices use the same framework files when running the application.
The postbuild.sh
script will now run at the end of the build process and remove the extra binary (depending on the target device for your build) from the framework bundled into your application. This step is required for submission of an application to iTunes.
Moving the app from Builder to Xcode¶
- App License and AppDelegate
First, edit the AppDelegate files. Xcode automatically generates AppDelegate files when you create a project. These files are AppDelegate.h and AppDelegate.m if you are using Objective-C. The file is AppDelegate.swift if you are using Swift.
(Note, additions to be made to your code are rendered here and throughout the document in blue font.)
If your project is written in Objective-C, edit the AppDelegate.h
file to look like this:
#import <UIKit/UIKit.h> @import P2UXApp; @interface AppDelegate : UIResponder <UIApplicationDelegate, P2UXAppCreatorDelegate> @property (strong, nonatomic) UIWindow *window; @end
Edit the AppDelegate.m
file to look like this:
#import "AppDelegate.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSString* appKey = @"xxxxx"; NSDictionary* opts; #if DEBUG opts = @{P2UXAppCreator_Opt_Env: P2UXAppCreator_Opt_Env_Stage}; #endif [P2UXAppCreator createApplicationWithKey:appKey opts:opts resources:nil delegate:self]; return YES; } ... @end
If your project is written in Swift, edit the AppDelegate.swift
file to look like this:
import UIKit import P2UXApp @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, P2UXAppCreatorDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { let appKey = "xxxxx"; var opts : [AnyHashable : Any]; #if DEBUG opts = [ P2UXAppCreator_Opt_Env: P2UXAppCreator_Opt_Env_Prototype] #endif P2UXAppCreator.createApplication(withKey: appKey, opts: opts, resources: nil, delegate: self) return true } ... }
The AppDelegate calls the P2UXAppCreator
method createApplication
using the appKey, which initializes the PRL with the application information. In this example, options are supplied to the createApplication
method to use the prototype version of the application when the application is compiled for debugging. To use the production version of the application for debugging, remove the options.
Next, retrieve the app’s license. In Builder, to the right of the publish button are further options in a drop-down menu.  Copy the license. In AppDelegate, replace the xxxxx in the line that reads appKey = @”xxxxx"; with your app’s license (retrieved earlier from Builder.)
Note
At this point the application setup is complete and the app should run successfully.
The PUB and network connectivity¶
The next step in the process requires developer awareness of the default PUB status and access to a network.
By default, the application accesses the PUB dynamically. This means that when the application is first installed, the P2UX rendering library (PRL) will authenticate the application key and then download the PUB before running the application content.
The first run of an application requires network connectivity. Otherwise, P2UX will return an error. The PUB’s default update policy is automatic. This means that the PRL will automatically check for updates each time the application runs. The library will also download any updates that are available, and then notify the user that the application will restart to apply any updates.
Static Assets¶
In some cases, a developer may opt to use only static assets rather than require network access for an app. In this situation, the PUB can be added to the application as a collection of static assets. To achieve this, follow these steps:
Note
This feature requires downloading your application PUB from Builder. This feature will be integrated as part of the P2UX Coordinator application for Mac OS
- In Builder, download the published PUB for application
- Steps to download PUB will go here
- Unzip the PUB files and copy the assets into a folder inside your project directory.
- In Xcode, add the folder to the project.
- From the project navigator, select the group folder with your application name.
- Right click and select Add Files to ‘app name’
- From the dialog, click the Options button in the bottom left corner and select Create folder References from the Added folders option
- Select the folder containing the PUB assets and click the Add button to add them to your project.
In the example, this folder is called phone_pub
.
In order to incorporate these files into your project, as well as to adjust the resource use settings, you must change the AppDelegate file.
For projects in Objective-C, edit the AppDelegate.m
file to look like this:
#import "AppDelegate.h" #import "SampleBehavior.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSString* appKey = @"xxxxx"; NSDictionary *opts; #if DEBUG opts = @{P2UXAppCreator_Opt_Env: P2UXAppCreator_Opt_Env_Prototype}; #endif NSDictionary *resources = @[ @{P2UXApp_PackageAttrib_FormFactor: [NSNumber numberWithInteger:P2UXFormFactor_Phone], P2UXApp_PackageAttrib_Type:P2UXApp_PackageType_Static, P2UXApp_PackageAttrib_Package:@"phone_pub", P2UXApp_PackageAttrib_Update:P2UXApp_PackageUpdate_None}]; [P2UXAppCreator createApplicationWithKey:appKey opts:opts resources:resources delegate:self]; return YES; } @end
For projects in Swift, edit the AppDelegate.swift
file to look like this:
import UIKit import P2UXApp @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, P2UXAppCreatorDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { let appKey = "xxxxx"; var opts : [AnyHashable : Any]; #if DEBUG opts = [ P2UXAppCreator_Opt_Env: P2UXAppCreator_Opt_Env_Prototype ] #endif var phoneResources: [AnyHashable : Any] = [ P2UXApp_PackageAttrib_FormFactor: P2UXFormFactor.phone, P2UXApp_PackageAttrib_Type: P2UXApp_PackageType_Static, P2UXApp_PackageAttrib_Package: "phone_pub", P2UXApp_PackageAttrib_Update: P2UXApp_PackageUpdate_None ] var resources : [Any] = [ phoneResources ] P2UXAppCreator.createApplication(withKey: appKey, opts: opts, resources: resources, delegate: self) return true } }
Defining Custom Resource Attributes¶
If desired, the developer can define specific resource attributes for the app. These attributes define where the assets of the application are located and how those assets are updated.
The resources parameter is an array of objects. Each object in the array defines the PUB usage for a particular form factor (Phone, Tablet, TV) using key value pairs. If the application supports multiple form factors, create an object in the resources array for each form factor.
Customize the resource attributes according to the possibilities below:
| Resource Attribute | Description |
|---|---|
| P2UXApp_PackageAttrib_FormFactor | Defines which form factor the attributes reference. Possible Values: P2UXFormFactor_Phone P2UXFormFactor_Tablet P2UXFormFactor_TV |
| P2UXApp_PackageAttrib_Type | Defines the type of resources for the form factor Possible Values: P2UXApp_PackageType_Static P2UXApp_PackageType_Remote |
| P2UXApp_PackageAttrib_Package | Defines the name of the folder within the application bundle containing assets when the P2UXApp_PackageAttrib_Type is P2UXApp_PackageType_Static. |
| P2UXApp_PackageAttrib_Update | Defines how to update the application assets Possible Values: P2UXApp_PackageUpdate_None P2UXApp_PackageUpdate_Auto P2UXApp_PackageUpdate_Manual |
After defining the resources, change the resources line in the app code from “nil” to “resources” (as highlighted in the example code above).


FRC - 623
Our FRC team 623
The Oakton Robotics Club was founded in 2001 by Mr. Scholla. Originally, it was called the Oakton High School Robotics, Rocketry, and Jets Club, however the Jets club was later disbanded due to lack of interest. The robotics club thrived and was made a competitive club with an application process and now has a diverse group of 50 students. We pride ourselves as a club not to discriminate students by their grade or gender and let everyone have the right to participate in FTC or FRC competitions. Our parent board make sure to keep the club running smoothly by ordering parts and they handle any thing related to finances so we can focus on building the robot. We also have numerous mentors with knowledge of robotics who help students with using the machinery and with any other problems they may face.
Our FRC team 623
Our FTC teams
The business team helps keep everyone organized and manages outreach events and food
We rely on generous sponsors to help keep our team running smoothly.
As a team, we want to spread STEM to younger students
Amazing photos of our teams in action.
Forms for current members
Info on joinig the team
Resources for current and prospective members
Lockheed Martin not only supports us financially, but also provides us a team mentor, Tom Convery. He shares the company's respect for leadership, community, and technology, and encourages us to do the same.
Bechtel’s high regards inspire our team to keep their qualities in mind when planning, building, and competing alike with their generous financial support and assistance.
Octo pushes us to furter innovate on our robot designs.
Leidos and their innovation of technology inspire us to work hard. The support they provide for us is something we cherish.


{include file="header"}
{{address.province}}{{address.city}}{{address.district}}{{address.address}}
{{goods.goods_name}}
规格：{{option_name}}
数量：{{goods.quantity}}
¥{{goods.price}}
合计: ¥{{total_price | number:2}}


{% extends "main.html" %} {% block body %} {% with messages = get_flashed_messages() %} {% if messages %} {% for message in messages %}
Do you really want to delete the following User:
Edit user information. Unset password will be ignored.
ERROR:


Slides available at: bit.ly/CnCjQuery
| JavaScript | Java |
|---|---|
| Netscape | Sun Microsystems |
| Object Oriented Scripting Language | Object Oriented Programming Language |
| Primarily Client-Side | Server-side |
html
/ \
head body
/ \ / \
meta link nav div
Selector - Picks out the element to manipulate
element: div, p, h1, etc
#id-selector: #my-id, #btn-submit, etc
.class-selector: .my-class, .container, etc
var myIngredient = "Vodka";
Function - Takes input, processes the input and produces output
function cocktailShaker (vodka, cappelletti, lime, sugar, pellegrino) {
var cocktail = vodka + cappelletti + lime + sugar + pellegrino;
return cocktail;
}
Like a <link> tag in the html  section connects your CSS, a

If your script file depends on another script file (as our script file depends jQuery), the dependancy has to be loaded prior to the script that depends on it so in our case the jQuery script tag has to come before our script tag.
$ is an alias for the jQuery function
$('p') = jQuery('p')
Allows for shorter, faster coding
We want our code to be able to run as soon as the page is ready - as soon as the DOM heierarchy has been constructed.
$(document).ready();
$(document).ready(function () {
//your jQuery code goes in here
});
The function above is referred to as a "callback." This is executable code that is passed as a parameter to another function or piece fo code
In order to capture interactions and react to them we need to be able to pick out HTML elements
$() is used to select elements
The this keyword always refers to the element that was clicked and can come in handy for reacting to events.
Given the HTML:

My Section Title

Paragraph content. Not feeling creative.

Select the h2 with an element selector:
$('h2')
select the div with a class selector:
$('.main')
select the paragraph with an id selector:
$('#my-id')
In the case where an element is nested inside of another, the inner element is the child element and the outer element is the parent element.

About

Contact

ul is a child of the nav element and the nav element is a parent of the ul element.
Parent selection example using jQuery
Given the HTML:

About

Contact

select the nav element using the parent method:
$('ul').parent(); //nav element is selected
Capture the action on an element and tell the browser what to do when it occurs.
Given the HTML:

<form>
First name:

<input type="text" name="firstname">

Last name:

<input type="text" name="lastname">
</form>
<button>Submit</button>
Gather click event on the Submit button:
$('button').click(function () {
//code for what you want to do when
//the button is clicked goes here
});
These are things that happen when an event is handled!
When you add < & > around the element in the jquery function, you're creating an element instead of selecting it.
$('div')
$('
')
The above creates an element but how do we add that element to the page?
Updates and replaces content nested inside the selected element

This will get replaced!

$('div').html('
My Heading
');

My Heading

Adds content inside the selected element

Page Title

$('#main-header').append('
Sub Heading
');

Page Title

Sub Heading

If we ran the same append a second time we'd get:

Page Title

Sub Heading

Sub Heading

Sometimes you want to combine the value from a variable with other text. In order to do that we utilize what is called concatenation. In the same way that we use + to add numbers we can use it in jQuery to add strings together.
var myVar = 'Chocolate';
var newString = myVar + ' is delicious!';
//newString = "Chocolate is delicious!"
Keyboard shortcut: cmd+option+i on Macs, cmd+shift+i or F12 on Windows
Work through part 1 of tonight's worksheet
Work through part 2 of Tonight's Worksheet
#LadyDevs
#KCWiT
#CodingAndCocktailsKC