From a47e080a60964e99adc0b2ef04b10d59193af207 Mon Sep 17 00:00:00 2001 From: Ian Grigg Date: Fri, 23 Jul 2010 04:24:00 +0000 Subject: [PATCH] updated git-svn-id: http://svn.cacert.org/CAcert/Policies@1975 14b1bab8-4ef6-0310-b690-991c95c89dfd --- code/pd.php | 6 + code/policydecisions.class.php | 612 ++++++++++++++++++++++++++++ policy_group_decisions_summary.html | 265 ++++++++---- 3 files changed, 793 insertions(+), 90 deletions(-) create mode 100644 code/pd.php create mode 100644 code/policydecisions.class.php diff --git a/code/pd.php b/code/pd.php new file mode 100644 index 0000000..a237acd --- /dev/null +++ b/code/pd.php @@ -0,0 +1,6 @@ +load_from_webpage(); // this one, +$pd->html(); // see this for options on output +?> diff --git a/code/policydecisions.class.php b/code/policydecisions.class.php new file mode 100644 index 0000000..5cd99ba --- /dev/null +++ b/code/policydecisions.class.php @@ -0,0 +1,612 @@ +load_from_webpage(); // read in the data + * // $pd->save_to_cache_files(); // (or add these two.) + * // $pd->read_from_cache_files(); + * $pd->html(); // see this for options on output + */ + +namespace Misc { + class PolicyDecisions { // if you change name, also do XOXOX below + + const WIKIURL = 'wiki.cacert.org/'; + const HTTP = 'http:'; + const HTTPS ='https:'; + const WIKI = 'https://wiki.cacert.org'; + const POLICY_DECISIONS = 'http://wiki.cacert.org/PolicyDecisions'; + const POLICY_DECISIONSS = 'https://wiki.cacert.org/PolicyDecisions#'; + + private $votes; + private $urls; + private $names; + private $decisions; + private $state; + private $line_num; + + private function &read_all(&$handle) + { + $contents = array(); + while (!feof($handle)) { + $contents[] = fread($handle, 8192); + } + fclose($handle); + $x = join('', $contents); +// echo "opened $url, found " . strlen($x) . " chars\n
"; + return $x; + } + + private function &read_page($url) + { + $handle = fopen($url, 'rb'); + $x = $this->read_all($handle); + return $x; + } + + private function &read_file($name) + { + $x = ''; + if (!file_exists($name)) return $x; + + $handle = fopen($name, 'rb'); + $x = $this->read_all($handle); + return $x; + } + + + + public function save_to_cache_files() + { + $test = true; + $this->write_cache_file('decisions', $this->decisions, 'decision', $test); + $this->write_cache_file('votes', $this->votes, '', $test); + $this->write_cache_file('names', $this->names, 'index', $test); + } + + public function read_from_cache_files() + { + $this->decisions = $this->read_cache_file('decisions'); + $this->votes = $this->read_cache_file('votes'); + $this->names = $this->read_cache_file('names'); + } + + public function write_cache_file($name, &$list, $keyname, $test = false) + { + $handle = fopen( $this->name_to_filename($name), 'wb' ); + + $time = time(); + $count = count($list); + $lines = array("v1;$name;$time;$count;json-array;$keyname"); + + foreach ($list as $entry) { + $lines[] = json_encode($entry); + } + + $data = join("\n", $lines); + fwrite($handle, $data); + fclose($handle); + + if ($test) { + $result = $this->read_cache_file($name); + foreach ($list as $key => $entry) { + $res_entry = $result[$key]; + if (! $res_entry ) { + $this->error("failed to recovered $key from cache."); +// echo "
\n"; +// print_r($entry); +// echo "
\n"; +// print_r($result); + exit(1); + } + if ($entry != $res_entry) { + $this->error("recovered $name not the same."); +// echo "
\n"; +// print_r(array_diff($res_entry, $entry)); +// echo "
\n"; +// print_r(array_diff($entry, $res_entry)); +// echo "
\n"; +// print_r($entry); +// echo "
\n"; +// print_r($res_entry); +// echo "
\n"; + exit(); + } + } + if ($result != $list) { + $this->error("recovered $name not the same."); +// echo "
\n"; +// print_r(array_diff($list, $result)); +// echo "
\n"; +// print_r(array_diff($result, $list)); +// echo "
\n"; +// print_r($result); +// echo "
\n"; +// print_r($list); +// echo "
\n"; + exit(); + } + } + } + + /* + * Prepended to cache files, don't forget a '/' if needed. + */ + public function &setCachePrefix($prefix) + { + $this->cache_prefix = $prefix; + } + + public function &name_to_filename($name) + { + return $this->cache_prefix . $name . '.txt'; + } + + /* + * The array key can be set to some string + * from the array entry named keyname, if supplied. + */ + public function &read_cache_file($name) + { + $data = $this->read_file( $this->name_to_filename($name) ); + $lines = explode("\n", $data); + $head = explode(';', $lines[0]); + $count = $head[3]; + $keyname = $head[5]; + $count2 = count($lines); + if ($count + 1 != count($lines)) { + $this->error("$name: $count+1 != $count2, lines mismatch"); + } + +// echo "decision key: $keyname / count == $count
\n"; + + $output = array(); + for ($i = 1; $i <= $count; $i ++) { + $recovered = json_decode($lines[$i], true); +// echo "$count: from " . $lines[i] . "\n
"; +// print_r($recovered); + if ($keyname) { + $key = $recovered[$keyname]; +// echo "\n
recovered $key from $keyname\n
"; + $output[$key] = $recovered; + } else { + $output[] = $recovered; + } +// exit(); + } + + return $output; + } + + + + private function error($e) + { + echo $this->line_num . ": " . $e . "
\n"; + } + private function herror($e) + { + echo $this->line_num . ": " . htmlentities($e) . "
\n"; + } + + private function vote_plus_one($name, $url, $act) + { + $best_uniq = $this->name_of_contributor($name, $url); + $current_decision = $this->decision; + + // note this does not pick up duplicates... + // it could, but they shouldn't be in the source anyway. + $this->votes[] = array($current_decision, $best_uniq, $act); + } + + private function count_a_vote($vote, $act) + { + $matches = array(); + $v1 = trim($vote); + if (!$v1) + return; + + if (preg_match('/]*href="([^"]*)">([^<]*)<\/a>/i', $v1, $matches)) { + $name = $matches[2]; + $wikiurl = $matches[1]; + $this->vote_plus_one($name, $wikiurl, $act); + } elseif (preg_match('/([<>;,])/', $v1, $matches)) { + $chars = $matches[0]; + $this->herror("garbled name with $chars in $vote"); + } elseif (preg_match('/^([^<>]*)$/i', $v1, $matches)) { + $name = $matches[1]; + $this->vote_plus_one($name, '', $act); + } else { + $this->herror("unparsed name in $vote"); + } + } + + private function count_td($line, $act) + { + $v0 = preg_replace('/]*>/i', '', $line); + $v1 = preg_replace('/]*>/i', '', $v0); + $v2 = preg_replace('/<\/td>/i', '', $v1); + $v3 = preg_replace('/<\/p>/i', '', $v2); +// $this->error("stripped:\n$v3 ~~~~~~~~~~~~\n"); + + $votes = explode(",", $v3); + foreach ($votes as $v) { +// echo " [$v] "; + $this->count_a_vote($v, $act); + } + } + + private function get_name($url) + { + return $this->names[$url]['name']; + } + + private function get_best_uniq_name($name, $url) + { + return $url ? $url : $name; + } + + private function get_wikiname($name) + { + foreach ($this->names as $n) { + if ($n['name'] == $name) + return $n['url']; // if there is one, else empty string + } + return ''; + } + + private function name_of_contributor($name, $url = '') + { + if ($url) { + if (! array_key_exists($url, $this->names)) { + $this->names[$url] = array( + 'url' => $url, + 'name' => $name, + 'index' => $url, + ); + } + + return $url; + } else { + if (! array_key_exists($name, $this->names)) + $this->names[$name] = $name; + $this->names[$name] = array( + 'url' => '', + 'name' => $name, + 'index' => $name, + ); + return $name; + } + } + + private function resolved_by($name, $url = '') + { + $decision = $this->decision; + $this->decisions[$decision]['name'] = $name; // not needed + $this->decisions[$decision]['url'] = $url; + $this->vote_plus_one($name, $url, 'res'); + } + + private function state($l) + { + /* + * Extract the decision number and title from the Heading

+ */ + if (preg_match('/

/i', $l, $matches)) { + $decision = trim($matches[1]); + $title = trim($matches[2]); + $title = preg_replace('/_/', ' ', $title); + $this->decision = $decision; + $this->decisions[$decision] = array( + 'title' => trim($title), + 'decision' => trim($decision), + ); + $this->resolved = 1; + } + /* + * If we've just seen a decision number, then look out for who + * called for the resolution. + */ + if (1 == $this->resolved) + { + if (preg_match('/]*href="([^"]*)">([^<]*)<\/a>: *Resolved/i', $l, $matches)) { + $url = trim($matches[1]); + $name = trim($matches[2]); + $this->resolved_by($name, $url); + $this->name_of_contributor($name, $url); + $this->resolved = 0; +// echo "{$this->decision} matching '$url' / $name /
\n"; + } elseif (preg_match('/>([^:<>]*): *Resolved/i', $l, $matches)) { + $name = trim($matches[1]); + $this->resolved_by($name); +// echo "{$this->decision} matching '$name'
\n"; + $this->resolved = 0; + } + // else, the name of resolution proposer is not properly recorded. + } + + /* + * Search for the Votes, set state to count them on next line. + */ + if ('' == $this->vote_state) { + if (preg_match("/aye:/i", $l)) + $this->vote_state = 'aye'; + elseif (preg_match("/nay:/i", $l)) + $this->vote_state = 'nay'; + elseif (preg_match("/abstain:/i", $l)) + $this->vote_state = 'abs'; + } + elseif ($this->vote_state) + { + /* + * Counting votes. + */ +// $this->error("looking for TD\n===================\n$l\n-------------------"); + if (preg_match("//i", $l)) { + $this->count_td($l, $this->vote_state); + } + $this->vote_state = ''; + } + } + + public function load_from_webpage() + { + $data = $this->read_page(self::POLICY_DECISIONS); + $lines = explode("\n", $data); + + $this->vote_state = ''; + $this->resolved = 0; + $this->names = array(); + $this->votes = array(); + $this->decisions = array(); + + $this->line_num = 0; + foreach ($lines as $l) { + $this->line_num++; + $this->state($l); + } + } + + + + public function html_head($title) + { + $this->l(""); + $this->l(""); + $this->l(""); + $this->l(" "); + + $this->l(" $title"); + $this->l("\n"); + } + + function setLineWriter($x) { $this->lw = $x; } + + private function l($s, $and_this_comment = '') + { + if ($this->lw) { + $this->lw->l($s, $and_this_comment); + } else { + $this->out[] = $s; + } + } + + + public function init_output(&$lines = null) + { + if ($lines) { + $this->out &= $lines; + } else { + $this->out = array(); + } + } + + /* + * This is the major entry point for a simple output. + * Copy this and vary the output initialisation, and choice of tables. + */ + public function html() + { + $this->init_output(); + $this->html_head('Policy Group Decisions Summary'); + + $this->html_by_contributors(); + $this->html_by_decisions(); + + $this->html_tail('Policy Group Decisions Summary'); + $this->l(""); + echo join("\n", $this->out); + } + + public function html_by_contributors() + { + $count_contributors = count($this->names); + $votes_by_contributor = $this->get_votes_by_contributor(); + $count_acts = count($this->votes); + $count_decisions = count($this->decisions); + $this->l("

The Policy Group Hall of Fame

"); + $this->l("

Policy Group has $count_contributors contributors, with a total $count_acts acts of participation. Each act is a vote cast or a decision proposed.

"); + $this->l("

"); + $this->table_votes($votes_by_contributor); + } + + public function html_tail() + { + $this->l("
"); + $url = self::POLICY_DECISIONS; + $link = "
$url"; + $this->l(" This summary wiki-scraped from $link, the formal record of Policy Decisions of the Policy Group. "); + $this->l(""); + } + + public function html_by_decisions() + { + $this->l("

"); + $this->l("

Summary of Decisions

\n

$count_decisions decisions issued by Policy Group

"); + $this->l("

"); + $this->table_decisions(); + } + + private function count_votes(&$votes_by_contributor) + { + $count = 0; + foreach ($votes_by_contributor as $entry) { + $count += $entry[3]; + } + return $count; + } + + static function cmp($a, $b) + { + if ($a['count'] < $b['count']) return +1; + if ($a['count'] > $b['count']) return -1; + return 0; + } + + private function &get_votes_by_contributor() + { + $sort = array(); + foreach ($this->votes as $vote) { + $decision = $vote[0]; + $uniq = $vote[1]; + $act = $vote[2]; + + if (! array_key_exists($uniq, $sort)) { + $sort[$uniq] = array( + 'uniq' => $uniq, + 'decisions' => array(), 'count' => 0, + 'aye' => 0, 'nay' => 0, 'res' => 0, 'abs' => 0, + ); + } + + $sort[$uniq]['decisions'][] = $decision; + + switch ($act) { + case 'aye': case 'nay': case 'res': case 'abs': + $sort[$uniq][$act] += 1; + break; + default: + $this->error("$decision: $uniq = $act? is what act?"); + } + + $sort[$uniq]['count'] += 1; + } + + // echo "OK, class name is " . get_class($this) . "
\n"; + usort($sort, array(get_class($this), "cmp")); // XOXOX class name + return $sort; + } + + private function table_votes(&$votes_by_contributor) + { + $this->l(""); + $this->l(""); + foreach ($votes_by_contributor as $entry) { + $most_actions = $entry['count']; + break; + } + $this->l(" "); + $this->l(" "); + $this->l(""); + + $td = ""; + $widths = str_repeat($td, $most_actions); + $this->l(" $widths "); + + foreach ($votes_by_contributor as $url => $entry) { + $this->l($this->get_contributor_line($entry, $most_actions)); + } + $this->l("
Name#ActsAyeNayAbsRes


\n"); + } + + private function get_contributor_line($entry, $most_actions) + { + $name = $this->get_name_link($entry['uniq']); + $count = $entry['count']; + $decisions = $entry['decisions']; + $aye = $entry['aye'] ? $entry['aye'] : ' '; + $nay = $entry['nay'] ? $entry['nay'] : ' '; + $abs = $entry['abs'] ? $entry['abs'] : ' '; + $res = $entry['res'] ? $entry['res'] : ' '; + $lead = " " . + "$name" . + "{$entry['count']}" . + "\n"; + $mix = array(); + $purl = self::POLICY_DECISIONSS; + for ($i = 1; $i <= $most_actions; $i++) { + $d = array_pop($decisions); + if ($d) { + $mix[] = "" . + "*" . + ""; + } else { + $mix[] = ""; + } + } + + $final = "$aye" . + "$nay" . + "$abs" . + "$res" . + "" . + "\n"; + $x = $lead . join('', $mix) . $final; + return $x; + } + + private function table_decisions() + { + $this->l(""); + $this->l(""); + foreach ($this->decisions as $number => $decision) { + $title = $decision['title']; + $name = $decision['name']; + $url = $decision['url']; + $name = $this->to_name_link($name, $url); + $pnumber = '$number"; + $this->l(" "); + } + $this->l("
NumberProposorTitle
$pnumber$name$title
"); + } + + private function to_name_link($name, $url) + { + if ($url && ($url != $name)) { + if (preg_match(",^/,", $url)) + $url = self::WIKI . $url; + $name = "$name"; + } + return $name; + } + + private function get_name_link($uniq) + { + if ('/' == $uniq[0]) { // is a url-based name + $url = $uniq; + $name = $this->get_name($uniq); + $display = "$name"; + } else { + $display = $uniq; + } + return $display; + } + + } +} + +/* +$pd = new PolicyDecisions(); +$pd->load_from_webpage(); +// $pd->save_to_cache_files(); +// $pd->read_from_cache_files(); +$pd->html(); +*/ + +?> diff --git a/policy_group_decisions_summary.html b/policy_group_decisions_summary.html index 2f0942e..d74a7cc 100644 --- a/policy_group_decisions_summary.html +++ b/policy_group_decisions_summary.html @@ -1,153 +1,239 @@ - + + Policy Group Decisions Summary

The Policy Group Hall of Fame

-

Policy Group has 64 contributors, with a total 300 acts of participation. Each act is a vote cast or a decision proposed.

-

+

Policy Group has 68 contributors, with a total 349 acts of participation. Each act is a vote cast or a decision proposed.

+

- - + + + + + + - - - - + + + + + + + - - - - + + + + + + + + + + + + + + + + - - - - - - + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + - - - - + - - + + + + + + + + + + + + + + + + + - - + + + + - - - - - - - - - - + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - + + + - - - - - - - - - - - - - + + + - - - - - - + - - - - - - + + + + + + + + + + + + + - - + + + + + + + + + + + + + +
Name#ActsAyeNayAbsRes


Teus30
Name#ActsAyeNayAbsRes


Teus30 ******************************18 12
Philipp D20********************151 4
Iang19*******************62 11
Philipp D24************************173 4
Iang23***********************64 13
Ted15 ***************132
Lambert13*************121
Philipp G11***********8111
Lambert14**************1211
Philipp G13*************10111
Faramir11***********821
Ulrich11***********64 1
Daniel11***********62 3
Greg11 ***********11
Tomáš10**********91
Faramir10**********82
Jens Paul9*********7 2
Tomáš11***********101
Pieter10**********82
Sam9 *********63
Pieter8********71
Ulrich8********52 1
Daniel7*******5 2
Brian7*******7
Alexander6******5 1
Brian9*********81
Jens Paul9*********7 2
Alexander7*******6 1
hugi6******42
Robert Cruikshank6 ******6
Morten6 ******51
Michael5 *****5
Andreas5*****41
Mario5*****32
Bernd5*****32
Guillaume4 ****4
Nick Bebout4 ****4
Alejandro Mery4 ****4
Mario4****22
Martin4****4
Pete Stephenson4 ****31
Andreas4****31
hugi4****31
Maurice4 ****4
Evaldo3***3
Nathan Tuggy4****4
Laura3***3
Hans Verbeek3***21
Werner3 ***3
Sascha Thomas Spreitzer3***2 1
Evaldo3***3
Fred Trotter3 ***21
Hans Verbeek3***21
Mark Lipscombe3***21
Michael Diederich3 ***3
Nathan3***3
Laura3***3
Raoul2**2
Ron Pettigrew2**2
Dominik2**2
Morten Gulbrandsen2**1 1
ernie2**2
Markus2 **2
Martin2**2
Brian Henson2**2
Mario2 **11
Roberto2**2
Dieter2**2
Mathieu2**2
Brian Henson2**2
Ron Pettigrew2**2
Raoul2**2
Dominik2**2
Andrew1*1
Wim1*1
Sebastian1 *1
Asbjørn1*1
Jac Kersing1 *1
Peter1
Svenne1 *1
John Moore III1 *1
Andrew1*1
Wim1*1
Svenne1*1
Joost1*1
Roberto1*1
Mathieu1*1
Dieter1
Barry1 *1
Dirk1 *1
Bernd1*1
Wytze1*1
Barry1*1
Kyle1 *1
Thomas Kuehn1*1
Mark L1*1
Gero1* 1
Wytze1*1
Gregory Engels1*1
Peter Williams1* 1
Joost1*1
Marty1 * 1
ernie1*1
Asbjørn1*1
Rasika Dayarathna1 *1
Thomas Kuehn1*1
Gero1* 1
Peter1*1
-

+ +

Summary of Decisions

-

38 decisions issued by Policy Group

-

+

decisions issued by Policy Group

+

+ + + + - + @@ -183,7 +269,6 @@
NumberProposorTitle
p20100722IangLicense our Policies under CC-BY-SA-3.0-AU
p20100710IangLicense root under Root Distribution License
p20100627Sascha Thomas SpreitzerLicense root under CC-BY-ND
p20100624DanielCCA defining .22CAcert Services.22
p20100510IangSecurity Policy to DRAFT
p20100426IangCCS to DRAFT
p20100401IangVETO takes a policy to WIP Document
p20100327Remove Board background checks from DRAFT Security Policy -- VACATED
A20100327Remove Board background checks from DRAFT Security Policy -- VACATED
p20100326IangSecurity Policy to remain in DRAFT
p20100306IangPolicy Officer makes minor adjustments
p20100120AlexanderAssurance Policy: require government ID
p20070918.1Jens PaulPolicy on Organisation Assurance
p-XXX-20070918.2Jens PaulOrganisation Assurance sub-policy for Germany
- - -
This summary wiki-scraped from wiki.cacert.org/PolicyDecisions, the formal record of Policy Decisions of the Policy Group. +
+ This summary wiki-scraped from http://wiki.cacert.org/PolicyDecisions, the formal record of Policy Decisions of the Policy Group.