diff --git a/Spyc.php b/Spyc.php new file mode 100644 index 0000000..1b23f5e --- /dev/null +++ b/Spyc.php @@ -0,0 +1,1147 @@ + + * @author Chris Wanstrath + * @link http://code.google.com/p/spyc/ + * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @package Spyc + */ + +if (!function_exists('spyc_load')) { + /** + * Parses YAML to array. + * @param string $string YAML string. + * @return array + */ + function spyc_load ($string) { + return Spyc::YAMLLoadString($string); + } +} + +if (!function_exists('spyc_load_file')) { + /** + * Parses YAML to array. + * @param string $file Path to YAML file. + * @return array + */ + function spyc_load_file ($file) { + return Spyc::YAMLLoad($file); + } +} + +if (!function_exists('spyc_dump')) { + /** + * Dumps array to YAML. + * @param array $data Array. + * @return string + */ + function spyc_dump ($data) { + return Spyc::YAMLDump($data, false, false, true); + } +} + +/** + * The Simple PHP YAML Class. + * + * This class can be used to read a YAML file and convert its contents + * into a PHP array. It currently supports a very limited subsection of + * the YAML spec. + * + * Usage: + * + * $Spyc = new Spyc; + * $array = $Spyc->load($file); + * + * or: + * + * $array = Spyc::YAMLLoad($file); + * + * or: + * + * $array = spyc_load_file($file); + * + * @package Spyc + */ +class Spyc { + + // SETTINGS + + const REMPTY = "\0\0\0\0\0"; + + /** + * Setting this to true will force YAMLDump to enclose any string value in + * quotes. False by default. + * + * @var bool + */ + public $setting_dump_force_quotes = false; + + /** + * Setting this to true will forse YAMLLoad to use syck_load function when + * possible. False by default. + * @var bool + */ + public $setting_use_syck_is_possible = false; + + + + /**#@+ + * @access private + * @var mixed + */ + private $_dumpIndent; + private $_dumpWordWrap; + private $_containsGroupAnchor = false; + private $_containsGroupAlias = false; + private $path; + private $result; + private $LiteralPlaceHolder = '___YAML_Literal_Block___'; + private $SavedGroups = array(); + private $indent; + /** + * Path modifier that should be applied after adding current element. + * @var array + */ + private $delayedPath = array(); + + /**#@+ + * @access public + * @var mixed + */ + public $_nodeId; + +/** + * Load a valid YAML string to Spyc. + * @param string $input + * @return array + */ + public function load ($input) { + return $this->__loadString($input); + } + + /** + * Load a valid YAML file to Spyc. + * @param string $file + * @return array + */ + public function loadFile ($file) { + return $this->__load($file); + } + + /** + * Load YAML into a PHP array statically + * + * The load method, when supplied with a YAML stream (string or file), + * will do its best to convert YAML in a file into a PHP array. Pretty + * simple. + * Usage: + * + * $array = Spyc::YAMLLoad('lucky.yaml'); + * print_r($array); + * + * @access public + * @return array + * @param string $input Path of YAML file or string containing YAML + */ + public static function YAMLLoad($input) { + $Spyc = new Spyc; + return $Spyc->__load($input); + } + + /** + * Load a string of YAML into a PHP array statically + * + * The load method, when supplied with a YAML string, will do its best + * to convert YAML in a string into a PHP array. Pretty simple. + * + * Note: use this function if you don't want files from the file system + * loaded and processed as YAML. This is of interest to people concerned + * about security whose input is from a string. + * + * Usage: + * + * $array = Spyc::YAMLLoadString("---\n0: hello world\n"); + * print_r($array); + * + * @access public + * @return array + * @param string $input String containing YAML + */ + public static function YAMLLoadString($input) { + $Spyc = new Spyc; + return $Spyc->__loadString($input); + } + + /** + * Dump YAML from PHP array statically + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as nothing.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + * @param int $no_opening_dashes Do not start YAML file with "---\n" + */ + public static function YAMLDump($array, $indent = false, $wordwrap = false, $no_opening_dashes = false) { + $spyc = new Spyc; + return $spyc->dump($array, $indent, $wordwrap, $no_opening_dashes); + } + + + /** + * Dump PHP array to YAML + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. Pretty simple. Feel free to + * save the returned string as tasteful.yaml and pass it around. + * + * Oh, and you can decide how big the indent is and what the wordwrap + * for folding is. Pretty cool -- just pass in 'false' for either if + * you want to use the default. + * + * Indent's default is 2 spaces, wordwrap's default is 40 characters. And + * you can turn off wordwrap by passing in 0. + * + * @access public + * @return string + * @param array $array PHP array + * @param int $indent Pass in false to use the default, which is 2 + * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) + */ + public function dump($array,$indent = false,$wordwrap = false, $no_opening_dashes = false) { + // Dumps to some very clean YAML. We'll have to add some more features + // and options soon. And better support for folding. + + // New features and options. + if ($indent === false or !is_numeric($indent)) { + $this->_dumpIndent = 2; + } else { + $this->_dumpIndent = $indent; + } + + if ($wordwrap === false or !is_numeric($wordwrap)) { + $this->_dumpWordWrap = 40; + } else { + $this->_dumpWordWrap = $wordwrap; + } + + // New YAML document + $string = ""; + if (!$no_opening_dashes) $string = "---\n"; + + // Start at the base of the array and move through it. + if ($array) { + $array = (array)$array; + $previous_key = -1; + foreach ($array as $key => $value) { + if (!isset($first_key)) $first_key = $key; + $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array); + $previous_key = $key; + } + } + return $string; + } + + /** + * Attempts to convert a key / value array item to YAML + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) { + if (is_array($value)) { + if (empty ($value)) + return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array); + // It has children. What to do? + // Make it the right kind of item + $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array); + // Add the indent + $indent += $this->_dumpIndent; + // Yamlize the array + $string .= $this->_yamlizeArray($value,$indent); + } elseif (!is_array($value)) { + // It doesn't have children. Yip. + $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array); + } + return $string; + } + + /** + * Attempts to convert an array to YAML + * @access private + * @return string + * @param $array The array you want to convert + * @param $indent The indent of the current level + */ + private function _yamlizeArray($array,$indent) { + if (is_array($array)) { + $string = ''; + $previous_key = -1; + foreach ($array as $key => $value) { + if (!isset($first_key)) $first_key = $key; + $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array); + $previous_key = $key; + } + return $string; + } else { + return false; + } + } + + /** + * Returns YAML from a key and a value + * @access private + * @return string + * @param $key The name of the key + * @param $value The value of the item + * @param $indent The indent of the current node + */ + private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) { + // do some folding here, for blocks + if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false || + strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, ' ') !== false || + strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 || + substr ($value, -1, 1) == ':') + ) { + $value = $this->_doLiteralBlock($value,$indent); + } else { + $value = $this->_doFolding($value,$indent); + } + + if ($value === array()) $value = '[ ]'; + if ($value === "") $value = '""'; + if (self::isTranslationWord($value)) { + $value = $this->_doLiteralBlock($value, $indent); + } + if (trim ($value) != $value) + $value = $this->_doLiteralBlock($value,$indent); + + if (is_bool($value)) { + $value = $value ? "true" : "false"; + } + + if ($value === null) $value = 'null'; + if ($value === "'" . self::REMPTY . "'") $value = null; + + $spaces = str_repeat(' ',$indent); + + //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) { + if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) { + // It's a sequence + $string = $spaces.'- '.$value."\n"; + } else { + // if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"'); + // It's mapped + if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; } + $string = rtrim ($spaces.$key.': '.$value)."\n"; + } + return $string; + } + + /** + * Creates a literal block for dumping + * @access private + * @return string + * @param $value + * @param $indent int The value of the indent + */ + private function _doLiteralBlock($value,$indent) { + if ($value === "\n") return '\n'; + if (strpos($value, "\n") === false && strpos($value, "'") === false) { + return sprintf ("'%s'", $value); + } + if (strpos($value, "\n") === false && strpos($value, '"') === false) { + return sprintf ('"%s"', $value); + } + $exploded = explode("\n",$value); + $newValue = '|'; + $indent += $this->_dumpIndent; + $spaces = str_repeat(' ',$indent); + foreach ($exploded as $line) { + $newValue .= "\n" . $spaces . ($line); + } + return $newValue; + } + + /** + * Folds a string of text, if necessary + * @access private + * @return string + * @param $value The string you wish to fold + */ + private function _doFolding($value,$indent) { + // Don't do anything if wordwrap is set to 0 + + if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) { + $indent += $this->_dumpIndent; + $indent = str_repeat(' ',$indent); + $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent"); + $value = ">\n".$indent.$wrapped; + } else { + if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY) + $value = '"' . $value . '"'; + if (is_numeric($value) && is_string($value)) + $value = '"' . $value . '"'; + } + + + return $value; + } + + private function isTrueWord($value) { + $words = self::getTranslations(array('true', 'on', 'yes', 'y')); + return in_array($value, $words, true); + } + + private function isFalseWord($value) { + $words = self::getTranslations(array('false', 'off', 'no', 'n')); + return in_array($value, $words, true); + } + + private function isNullWord($value) { + $words = self::getTranslations(array('null', '~')); + return in_array($value, $words, true); + } + + private function isTranslationWord($value) { + return ( + self::isTrueWord($value) || + self::isFalseWord($value) || + self::isNullWord($value) + ); + } + + /** + * Coerce a string into a native type + * Reference: http://yaml.org/type/bool.html + * TODO: Use only words from the YAML spec. + * @access private + * @param $value The value to coerce + */ + private function coerceValue(&$value) { + if (self::isTrueWord($value)) { + $value = true; + } else if (self::isFalseWord($value)) { + $value = false; + } else if (self::isNullWord($value)) { + $value = null; + } + } + + /** + * Given a set of words, perform the appropriate translations on them to + * match the YAML 1.1 specification for type coercing. + * @param $words The words to translate + * @access private + */ + private static function getTranslations(array $words) { + $result = array(); + foreach ($words as $i) { + $result = array_merge($result, array(ucfirst($i), strtoupper($i), strtolower($i))); + } + return $result; + } + +// LOADING FUNCTIONS + + private function __load($input) { + $Source = $this->loadFromSource($input); + return $this->loadWithSource($Source); + } + + private function __loadString($input) { + $Source = $this->loadFromString($input); + return $this->loadWithSource($Source); + } + + private function loadWithSource($Source) { + if (empty ($Source)) return array(); + if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) { + $array = syck_load (implode ("\n", $Source)); + return is_array($array) ? $array : array(); + } + + $this->path = array(); + $this->result = array(); + + $cnt = count($Source); + for ($i = 0; $i < $cnt; $i++) { + $line = $Source[$i]; + + $this->indent = strlen($line) - strlen(ltrim($line)); + $tempPath = $this->getParentPathByIndent($this->indent); + $line = self::stripIndent($line, $this->indent); + if (self::isComment($line)) continue; + if (self::isEmpty($line)) continue; + $this->path = $tempPath; + + $literalBlockStyle = self::startsLiteralBlock($line); + if ($literalBlockStyle) { + $line = rtrim ($line, $literalBlockStyle . " \n"); + $literalBlock = ''; + $line .= ' '.$this->LiteralPlaceHolder; + $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1])); + while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) { + $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent); + } + $i--; + } + + // Strip out comments + if (strpos ($line, '#')) { + $line = preg_replace('/\s*#([^"\']+)$/','',$line); + } + + while (++$i < $cnt && self::greedilyNeedNextLine($line)) { + $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t"); + } + $i--; + + $lineArray = $this->_parseLine($line); + + if ($literalBlockStyle) + $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock); + + $this->addArray($lineArray, $this->indent); + + foreach ($this->delayedPath as $indent => $delayedPath) + $this->path[$indent] = $delayedPath; + + $this->delayedPath = array(); + + } + return $this->result; + } + + private function loadFromSource ($input) { + if (!empty($input) && strpos($input, "\n") === false && file_exists($input)) + $input = file_get_contents($input); + + return $this->loadFromString($input); + } + + private function loadFromString ($input) { + $lines = explode("\n",$input); + foreach ($lines as $k => $_) { + $lines[$k] = rtrim ($_, "\r"); + } + return $lines; + } + + /** + * Parses YAML code and returns an array for a node + * @access private + * @return array + * @param string $line A line from the YAML file + */ + private function _parseLine($line) { + if (!$line) return array(); + $line = trim($line); + if (!$line) return array(); + + $array = array(); + + $group = $this->nodeContainsGroup($line); + if ($group) { + $this->addGroup($line, $group); + $line = $this->stripGroup ($line, $group); + } + + if ($this->startsMappedSequence($line)) + return $this->returnMappedSequence($line); + + if ($this->startsMappedValue($line)) + return $this->returnMappedValue($line); + + if ($this->isArrayElement($line)) + return $this->returnArrayElement($line); + + if ($this->isPlainArray($line)) + return $this->returnPlainArray($line); + + + return $this->returnKeyValuePair($line); + + } + + /** + * Finds the type of the passed value, returns the value as the new type. + * @access private + * @param string $value + * @return mixed + */ + private function _toType($value) { + if ($value === '') return ""; + $first_character = $value[0]; + $last_character = substr($value, -1, 1); + + $is_quoted = false; + do { + if (!$value) break; + if ($first_character != '"' && $first_character != "'") break; + if ($last_character != '"' && $last_character != "'") break; + $is_quoted = true; + } while (0); + + if ($is_quoted) { + $value = str_replace('\n', "\n", $value); + return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\'')); + } + + if (strpos($value, ' #') !== false && !$is_quoted) + $value = preg_replace('/\s+#(.+)$/','',$value); + + if ($first_character == '[' && $last_character == ']') { + // Take out strings sequences and mappings + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $value = array(); + foreach ($explode as $v) { + $value[] = $this->_toType($v); + } + return $value; + } + + if (strpos($value,': ')!==false && $first_character != '{') { + $array = explode(': ',$value); + $key = trim($array[0]); + array_shift($array); + $value = trim(implode(': ',$array)); + $value = $this->_toType($value); + return array($key => $value); + } + + if ($first_character == '{' && $last_character == '}') { + $innerValue = trim(substr ($value, 1, -1)); + if ($innerValue === '') return array(); + // Inline Mapping + // Take out strings sequences and mappings + $explode = $this->_inlineEscape($innerValue); + // Propagate value array + $array = array(); + foreach ($explode as $v) { + $SubArr = $this->_toType($v); + if (empty($SubArr)) continue; + if (is_array ($SubArr)) { + $array[key($SubArr)] = $SubArr[key($SubArr)]; continue; + } + $array[] = $SubArr; + } + return $array; + } + + if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') { + return null; + } + + if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){ + $intvalue = (int)$value; + if ($intvalue != PHP_INT_MAX) + $value = $intvalue; + return $value; + } + + if (is_numeric($value) && preg_match('/^0[xX][0-9a-fA-F]+$/', $value)) { + // Hexadecimal value. + return hexdec($value); + } + + $this->coerceValue($value); + + if (is_numeric($value)) { + if ($value === '0') return 0; + if (rtrim ($value, 0) === $value) + $value = (float)$value; + return $value; + } + + return $value; + } + + /** + * Used in inlines to check for more inlines or quoted strings + * @access private + * @return array + */ + private function _inlineEscape($inline) { + // There's gotta be a cleaner way to do this... + // While pure sequences seem to be nesting just fine, + // pure mappings and mappings with sequences inside can't go very + // deep. This needs to be fixed. + + $seqs = array(); + $maps = array(); + $saved_strings = array(); + $saved_empties = array(); + + // Check for empty strings + $regex = '/("")|(\'\')/'; + if (preg_match_all($regex,$inline,$strings)) { + $saved_empties = $strings[0]; + $inline = preg_replace($regex,'YAMLEmpty',$inline); + } + unset($regex); + + // Check for strings + $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; + if (preg_match_all($regex,$inline,$strings)) { + $saved_strings = $strings[0]; + $inline = preg_replace($regex,'YAMLString',$inline); + } + unset($regex); + + // echo $inline; + + $i = 0; + do { + + // Check for sequences + while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) { + $seqs[] = $matchseqs[0]; + $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1); + } + + // Check for mappings + while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) { + $maps[] = $matchmaps[0]; + $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1); + } + + if ($i++ >= 10) break; + + } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false); + + $explode = explode(',',$inline); + $explode = array_map('trim', $explode); + $stringi = 0; $i = 0; + + while (1) { + + // Re-add the sequences + if (!empty($seqs)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + foreach ($seqs as $seqk => $seq) { + $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value); + $value = $explode[$key]; + } + } + } + } + + // Re-add the mappings + if (!empty($maps)) { + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLMap') !== false) { + foreach ($maps as $mapk => $map) { + $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value); + $value = $explode[$key]; + } + } + } + } + + + // Re-add the strings + if (!empty($saved_strings)) { + foreach ($explode as $key => $value) { + while (strpos($value,'YAMLString') !== false) { + $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1); + unset($saved_strings[$stringi]); + ++$stringi; + $value = $explode[$key]; + } + } + } + + + // Re-add the empties + if (!empty($saved_empties)) { + foreach ($explode as $key => $value) { + while (strpos($value,'YAMLEmpty') !== false) { + $explode[$key] = preg_replace('/YAMLEmpty/', '', $value, 1); + $value = $explode[$key]; + } + } + } + + $finished = true; + foreach ($explode as $key => $value) { + if (strpos($value,'YAMLSeq') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLMap') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLString') !== false) { + $finished = false; break; + } + if (strpos($value,'YAMLEmpty') !== false) { + $finished = false; break; + } + } + if ($finished) break; + + $i++; + if ($i > 10) + break; // Prevent infinite loops. + } + + + return $explode; + } + + private function literalBlockContinues ($line, $lineIndent) { + if (!trim($line)) return true; + if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true; + return false; + } + + private function referenceContentsByAlias ($alias) { + do { + if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; } + $groupPath = $this->SavedGroups[$alias]; + $value = $this->result; + foreach ($groupPath as $k) { + $value = $value[$k]; + } + } while (false); + return $value; + } + + private function addArrayInline ($array, $indent) { + $CommonGroupPath = $this->path; + if (empty ($array)) return false; + + foreach ($array as $k => $_) { + $this->addArray(array($k => $_), $indent); + $this->path = $CommonGroupPath; + } + return true; + } + + private function addArray ($incoming_data, $incoming_indent) { + + // print_r ($incoming_data); + + if (count ($incoming_data) > 1) + return $this->addArrayInline ($incoming_data, $incoming_indent); + + $key = key ($incoming_data); + $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null; + if ($key === '__!YAMLZero') $key = '0'; + + if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values. + if ($key || $key === '' || $key === '0') { + $this->result[$key] = $value; + } else { + $this->result[] = $value; end ($this->result); $key = key ($this->result); + } + $this->path[$incoming_indent] = $key; + return; + } + + + + $history = array(); + // Unfolding inner array tree. + $history[] = $_arr = $this->result; + foreach ($this->path as $k) { + $history[] = $_arr = $_arr[$k]; + } + + if ($this->_containsGroupAlias) { + $value = $this->referenceContentsByAlias($this->_containsGroupAlias); + $this->_containsGroupAlias = false; + } + + + // Adding string or numeric key to the innermost level or $this->arr. + if (is_string($key) && $key == '<<') { + if (!is_array ($_arr)) { $_arr = array (); } + + $_arr = array_merge ($_arr, $value); + } else if ($key || $key === '' || $key === '0') { + if (!is_array ($_arr)) + $_arr = array ($key=>$value); + else + $_arr[$key] = $value; + } else { + if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; } + else { $_arr[] = $value; end ($_arr); $key = key ($_arr); } + } + + $reverse_path = array_reverse($this->path); + $reverse_history = array_reverse ($history); + $reverse_history[0] = $_arr; + $cnt = count($reverse_history) - 1; + for ($i = 0; $i < $cnt; $i++) { + $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i]; + } + $this->result = $reverse_history[$cnt]; + + $this->path[$incoming_indent] = $key; + + if ($this->_containsGroupAnchor) { + $this->SavedGroups[$this->_containsGroupAnchor] = $this->path; + if (is_array ($value)) { + $k = key ($value); + if (!is_int ($k)) { + $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k; + } + } + $this->_containsGroupAnchor = false; + } + + } + + private static function startsLiteralBlock ($line) { + $lastChar = substr (trim($line), -1); + if ($lastChar != '>' && $lastChar != '|') return false; + if ($lastChar == '|') return $lastChar; + // HTML tags should not be counted as literal blocks. + if (preg_match ('#<.*?>$#', $line)) return false; + return $lastChar; + } + + private static function greedilyNeedNextLine($line) { + $line = trim ($line); + if (!strlen($line)) return false; + if (substr ($line, -1, 1) == ']') return false; + if ($line[0] == '[') return true; + if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true; + return false; + } + + private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) { + $line = self::stripIndent($line, $indent); + if ($literalBlockStyle !== '|') { + $line = self::stripIndent($line); + } + $line = rtrim ($line, "\r\n\t ") . "\n"; + if ($literalBlockStyle == '|') { + return $literalBlock . $line; + } + if (strlen($line) == 0) + return rtrim($literalBlock, ' ') . "\n"; + if ($line == "\n" && $literalBlockStyle == '>') { + return rtrim ($literalBlock, " \t") . "\n"; + } + if ($line != "\n") + $line = trim ($line, "\r\n ") . " "; + return $literalBlock . $line; + } + + function revertLiteralPlaceHolder ($lineArray, $literalBlock) { + foreach ($lineArray as $k => $_) { + if (is_array($_)) + $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock); + else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) + $lineArray[$k] = rtrim ($literalBlock, " \r\n"); + } + return $lineArray; + } + + private static function stripIndent ($line, $indent = -1) { + if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line)); + return substr ($line, $indent); + } + + private function getParentPathByIndent ($indent) { + if ($indent == 0) return array(); + $linePath = $this->path; + do { + end($linePath); $lastIndentInParentPath = key($linePath); + if ($indent <= $lastIndentInParentPath) array_pop ($linePath); + } while ($indent <= $lastIndentInParentPath); + return $linePath; + } + + + private function clearBiggerPathValues ($indent) { + + + if ($indent == 0) $this->path = array(); + if (empty ($this->path)) return true; + + foreach ($this->path as $k => $_) { + if ($k > $indent) unset ($this->path[$k]); + } + + return true; + } + + + private static function isComment ($line) { + if (!$line) return false; + if ($line[0] == '#') return true; + if (trim($line, " \r\n\t") == '---') return true; + return false; + } + + private static function isEmpty ($line) { + return (trim ($line) === ''); + } + + + private function isArrayElement ($line) { + if (!$line || !is_scalar($line)) return false; + if (substr($line, 0, 2) != '- ') return false; + if (strlen ($line) > 3) + if (substr($line,0,3) == '---') return false; + + return true; + } + + private function isHashElement ($line) { + return strpos($line, ':'); + } + + private function isLiteral ($line) { + if ($this->isArrayElement($line)) return false; + if ($this->isHashElement($line)) return false; + return true; + } + + + private static function unquote ($value) { + if (!$value) return $value; + if (!is_string($value)) return $value; + if ($value[0] == '\'') return trim ($value, '\''); + if ($value[0] == '"') return trim ($value, '"'); + return $value; + } + + private function startsMappedSequence ($line) { + return (substr($line, 0, 2) == '- ' && substr ($line, -1, 1) == ':'); + } + + private function returnMappedSequence ($line) { + $array = array(); + $key = self::unquote(trim(substr($line,1,-1))); + $array[$key] = array(); + $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key); + return array($array); + } + + private function checkKeysInValue($value) { + if (strchr('[{"\'', $value[0]) === false) { + if (strchr($value, ': ') !== false) { + throw new Exception('Too many keys: '.$value); + } + } + } + + private function returnMappedValue ($line) { + $this->checkKeysInValue($line); + $array = array(); + $key = self::unquote (trim(substr($line,0,-1))); + $array[$key] = ''; + return $array; + } + + private function startsMappedValue ($line) { + return (substr ($line, -1, 1) == ':'); + } + + private function isPlainArray ($line) { + return ($line[0] == '[' && substr ($line, -1, 1) == ']'); + } + + private function returnPlainArray ($line) { + return $this->_toType($line); + } + + private function returnKeyValuePair ($line) { + $array = array(); + $key = ''; + if (strpos ($line, ': ')) { + // It's a key/value pair most likely + // If the key is in double quotes pull it out + if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) { + $value = trim(str_replace($matches[1],'',$line)); + $key = $matches[2]; + } else { + // Do some guesswork as to the key and the value + $explode = explode(': ', $line); + $key = trim(array_shift($explode)); + $value = trim(implode(': ', $explode)); + $this->checkKeysInValue($value); + } + // Set the type of the value. Int, string, etc + $value = $this->_toType($value); + if ($key === '0') $key = '__!YAMLZero'; + $array[$key] = $value; + } else { + $array = array ($line); + } + return $array; + + } + + + private function returnArrayElement ($line) { + if (strlen($line) <= 1) return array(array()); // Weird %) + $array = array(); + $value = trim(substr($line,1)); + $value = $this->_toType($value); + if ($this->isArrayElement($value)) { + $value = $this->returnArrayElement($value); + } + $array[] = $value; + return $array; + } + + + private function nodeContainsGroup ($line) { + $symbolsForReference = 'A-z0-9_\-'; + if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-) + if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; + if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1]; + if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1]; + if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1]; + return false; + + } + + private function addGroup ($line, $group) { + if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1); + if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1); + //print_r ($this->path); + } + + private function stripGroup ($line, $group) { + $line = trim(str_replace($group, '', $line)); + return $line; + } +} + +// Enable use of Spyc from command line +// The syntax is the following: php Spyc.php spyc.yaml + +do { + if (PHP_SAPI != 'cli') break; + if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break; + if (empty ($_SERVER['PHP_SELF']) || FALSE === strpos ($_SERVER['PHP_SELF'], 'Spyc.php') ) break; + $file = $argv[1]; + echo json_encode (spyc_load_file ($file)); +} while (0); \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..f5b67c8 --- /dev/null +++ b/index.php @@ -0,0 +1,104 @@ + $category_data) +{ + $bins[$category] = array( + "name" => $category_data["name"], + "description" => $category_data["description"], + "projects" => array() + ); +} + +foreach($data["projects"] as $project_name => $project_data) +{ + $cat = $project_data["category"]; + $project_data["name"] = $project_name; + + if(isset($bins[$cat])) + { + $bins[$cat]["projects"][] = $project_data; + } +} + +?> + + + + + Projects List + + + + + +
+

Projects List

+ +

+ This is a list of my projects. Active projects, abandoned projects, planned projects, everything. It may not yet be complete; changes will be made over time. +

+ +

+ If you're looking for my personal homepage, this is where you want to be. +

+ +

+ Each project indicates whether contributions are welcome or not. This refers primarily to code contributions (eg. in the form of a pull request). Bug reports may be accepted, even if code contributions aren't. If contributions are not accepted for a project, that generally means it is either undergoing an architectural change, in the design stages, or simply unmaintained. +

+ + $bin): ?> +
+

+

+ +
+ +
+ + + " class="top-bar link-repository pure-button" target="_blank"> Repository + + + +
Contributions are welcome!
+ +
Contributions not accepted
+ + + + " class="top-bar link-website pure-button" target="_blank"> Website + +
+ +
+

+ +

+ + v - + + + + +

+ + +

+ + +

+
+
+ +
+
+ +
+ + \ No newline at end of file diff --git a/projects.yaml b/projects.yaml new file mode 100644 index 0000000..201fd9a --- /dev/null +++ b/projects.yaml @@ -0,0 +1,480 @@ +categories: + maintained: + name: Actively Maintained + description: These projects are actively developed. Bug reports and feature suggestions are welcomed. Development is generally ongoing. + in_progress: + name: Work In Progress + description: These projects are currently being worked on, but are generally not yet in a usable state, or are getting a significant rewrite. + finished: + name: Finished + description: These projects are (usually) feature-complete, or no longer relevant. Small bugs may get fixed, but other than that no development occurs. + experiments: + name: Experiments + description: Just dabbling around with code. These projects may or may not turn into something useful. No guarantees. + on_hold: + name: On Hold + description: These are projects that are not currently in active development, but will be in the future. Reasons vary. + planned: + name: Planned + description: These are projects that are planned, but for which no (or extremely little) code exists yet. Typically in design stages. + unmaintained: + name: Unmaintained + description: The dead and the buried. These projects are abandoned, and no longer receive any updates. Use at your own risk. +projects: + Fleet: + category: planned + notes: This project consists of a number of other sub-projects. These sub-projects reference Fleet in their description or notes. + description: A distributed hosted services grid for non-profit projects. + contributions_accepted: no + PDF Inspector: + category: planned + description: A web-based PDF equivalent of Developer Tools, for debugging and taking apart PDF files. + contributions_accepted: no + Image Batcher: + category: planned + description: A GUI tool for batch-processing images using GraphicsMagick. + contributions_accepted: no + AnonNews: + category: in_progress + description: An uncensored news and discussion platform about Anonymous and (loosely) related topics. + notes: Currently undergoing a significant rewrite. + version: 2.0 + website: http://anonnews.org/ + repository: https://github.com/joepie91/anonnews2 + contributions_accepted: no + license: WTFPL / CC0 + ReDonate: + category: maintained + notes: Needs work. In particular in the area of statistics. + description: Recurring contributions, done right. + website: http://redonate.net/ + repository: https://github.com/joepie91/redonate + contributions_accepted: yes + license: WTFPL / CC0 + pastebin-scrape: + category: maintained + notes: Broke a while ago, then magically started working again. Reason unclear. + description: A resilient Pastebin.com scraper. + website: https://archive.org/details/pastebinpastes + repository: https://github.com/joepie91/pastebin-scrape + contributions_accepted: yes + license: WTFPL / CC0 + circd-node: + category: experiments + description: A second attempt at writing an IRCd, this time in Node.js. + repository: https://github.com/joepie91/circd-node + contributions_accepted: no + license: WTFPL / CC0 + pythonwhois: + category: maintained + description: A library for retrieving and parsing WHOIS data in Python. + version: 2.2.2 + website: http://cryto.net/pythonwhois + repository: https://github.com/joepie91/python-whois + contributions_accepted: yes + license: WTFPL / CC0 + PDFy: + category: maintained + description: A free instant PDF hosting and viewing service, that can be embedded into other websites. + website: http://pdf.yt/ + repository: https://github.com/joepie91/pdfy + contributions_accepted: yes + license: WTFPL / CC0 (pdf.js portions Apache 2.0) + node-ia: + category: in_progress + description: A Node.js port of the `internetarchive` Python library, for interacting with the Internet Archive S3 and Metadata APIs. + repository: https://github.com/joepie91/node-ia + contributions_accepted: no + license: WTFPL / CC0 + Cryto Team: + category: on_hold + notes: Currently on hold. A significant amount of code needs to be written before this is even remotely usable. + description: A project management and group collaboration platform for non-profit projects. + repository: https://github.com/joepie91/crytoteam + contributions_accepted: yes + license: WTFPL / CC0 + Cryto-Status: + category: in_progress + description: A realtime server and service monitoring system. + repository: https://github.com/joepie91/cryto-status + contributions_accepted: yes + license: WTFPL / CC0 + CPHP: + category: in_progress + notes: In a usable state, and already used in numerous of the projects here, but largely undocumented and no official 1.0 release yet. + description: An intuitive PHP framework that can be learned in 60 minutes. + repository: https://github.com/joepie91/cphp + contributions_accepted: yes + license: WTFPL / CC0 + Nexus: + category: in_progress + notes: An essential component of Fleet. + description: An arbitrary data and message routing daemon for distributed resource pools. + repository: https://github.com/joepie91/Nexus + contributions_accepted: yes + license: WTFPL / CC0 + Radium: + category: in_progress + description: A light-weight batteries-included HTML5 game engine. + repository: https://github.com/joepie91/radium + contributions_accepted: no + license: WTFPL / CC0 + vpslist: + category: on_hold + notes: Pending completion of a significant rewrite. + description: Web application for comparing VPS providers on various specifications, allowing for filtering and sorting. + website: http://vps-list.cryto.net/ + repository: https://github.com/joepie91/vpslist + contributions_accepted: yes + license: WTFPL / CC0 + zippydoc: + category: maintained + description: Documentation markup language and library, including HTML converter. + version: 1.2 + website: http://cryto.net/zippydoc + repository: https://github.com/joepie91/zippydoc + contributions_accepted: yes + license: WTFPL / CC0 + CVM: + category: on_hold + notes: Requires significant work before it is in a usable state. Please note that architecture-changing contributions are not currently accepted. + description: A free and open-source VPS panel. + repository: https://github.com/joepie91/cvm + contributions_accepted: yes + license: WTFPL / CC0 + Cryto Books: + category: on_hold + notes: Pending significant rewrite, of the crawler(s) in particular. Help is much appreciated. + description: An e-book crawler and search engine. + version: 1.0 + repository: https://github.com/joepie91/crytobooks + contributions_accepted: yes + license: WTFPL / CC0 + Tahoe-S3: + category: on_hold + notes: Put on hold as non-essential. Will eventually be used for Fleet, but will be preceded by a generic CDN frontend. + description: An S3-like API frontend and self-healing mechanism for Tahoe-LAFS. + repository: https://github.com/joepie91/tahoe-s3 + contributions_accepted: yes + license: WTFPL / CC0 + pytahoe: + category: maintained + notes: In need of some serious attention, capabilities are currently very limited. Usable for read-only usage, though. + description: A Python module for working with the Tahoe-LAFS filesystem. + version: 1.0.3 + repository: https://github.com/joepie91/pytahoe + contributions_accepted: yes + license: WTFPL / CC0 + openNG: + category: on_hold + notes: On hold, pending decisions about a change in technology stack. + description: An open-source node graph-style intelligence platform + repository: https://github.com/joepie91/openNG + contributions_accepted: no + license: WTFPL / CC0 + JSDE: + category: on_hold + notes: Newer, modified version using Angular.js incorporated in OpenNG. Future as a stand-alone project is uncertain. + description: Fully client-side 'desktop environment' in Javascript, intended for data processing web applications. + repository: https://github.com/joepie91/jsde + contributions_accepted: no + license: WTFPL / CC0 + Envoy: + category: on_hold + notes: Project was axed by employer. Development may continue independently in the future. + description: An XMPP platform designed for team collaboration. + repository: https://github.com/KnightSwarm/Envoy + contributions_accepted: yes + license: GPLv3 + Cryto.net: + category: on_hold + notes: More important projects to sort out currently. Will be resumed when there's time. + description: The new http://cryto.net/ website. + repository: https://github.com/joepie91/cryto-site + contributions_accepted: yes + license: WTFPL / CC0 + todo: + category: on_hold + notes: May get absorbed into a larger project involving externally pushed todo items. Hosted version will remain operational. + description: A todo web-app for overworked hackers. + repository: https://github.com/joepie91/todo + contributions_accepted: yes + license: WTFPL / CC0 + pyLSA: + category: on_hold + notes: Basic functionality works. Configuration and authentication code missing. + description: A self-contained simple statistics agent. + repository: https://github.com/joepie91/pyLSA + contributions_accepted: yes + license: WTFPL / CC0 + Cryto Learn: + category: on_hold + notes: Pending completion of a bunch of crawlers. This is quite a bit of work to do correctly. Internal architecture also needs some work. + description: A meta-search engine for online courses and educational materials. + website: http://learn.cryto.net/ + repository: https://github.com/joepie91/crytolearn + contributions_acceptd: yes + license: WTFPL / CC0 + pysfx: + category: maintained + description: Tool for creating self-extracting self-contained Python scripts with autorun functionality. + version: 0.1 + repository: https://github.com/joepie91/pysfx + contributions_accepted: yes + license: WTFPL / CC0 + resolv: + category: on_hold + notes: Resolvers need fixing. Architecture changes required to accomodate CAPTCHAs. + description: A Python module for resolving URLs of streaming sites and filehosters to direct download URLs. + version: 1.2.0 + repository: https://github.com/joepie91/resolv + contributions_accepted: yes + license: WTFPL / CC0 + emailparser: + category: finished + notes: No formal documentation. Use --help on the various scripts for instructions. + description: Parser and static HTML renderer for .eml files. + repository: https://github.com/joepie91/emailparser + contributions_accepted: yes + license: WTFPL / CC0 + ScraperScript: + category: experiments + notes: Functional. Future development undetermined. + description: A bookmarklet that helps you find unique selectors for page elements. + website: http://cryto.net/scraperscript/ + repository: https://github.com/joepie91/scraperscript + contributions_accepted: yes + license: WTFPL / CC0 + scantools: + category: maintained + description: An assortment of tools for scanning books. + repository: https://github.com/joepie91/scantools + contributions_accepted: yes + license: WTFPL / CC0 + Python Documentation: + category: on_hold + notes: Documentation takes a lot of time to write correctly. On hold indefinitely until I find the time. + description: An attempt at writing better Python documentation. + repository: https://github.com/joepie91/python-docs + contributions_accepted: yes + license: WTFPL / CC0 + filething: + category: maintained + description: A thin light-weight wrapper library, to make filesystem operations in Python suck less. + version: 1.0 + repository: https://github.com/joepie91/filething + contributions_accepted: yes + license: WTFPL / CC0 + image-disc: + category: finished + description: A small utility to batch-create archival-quality images of CDs/DVDs on Linux. + repository: https://github.com/joepie91/image-disc + contributions_accepted: yes + license: WTFPL / CC0 + wpcom-to-jekyll: + category: finished + description: A WordPress.com-to-Jekyll converter. + repository: https://github.com/joepie91/wpcom-to-jekyll + contributions_accepted: yes + license: WTFPL / CC0 + phenny: + category: maintained + notes: This is a fork of https://github.com/sbp/phenny. Additional plugins are developed from time to time. + description: A Python IRC bot. + repository: https://github.com/joepie91/phenny + contributions_accepted: yes + license: WTFPL / CC0 + nzbspider: + category: finished + description: A simple tool to automatically download NZBs for given releases. + repository: https://github.com/joepie91/nzbspider + contributions_accepted: yes + license: WTFPL / CC0 + circd: + category: unmaintained + description: My first attempt at writing an IRCd, in Python. + repository: https://github.com/joepie91/circd + contributions_accepted: no + license: WTFPL / CC0 + isohunt-grab: + category: finished + description: A seesaw pipeline for Isohunt archiving. + repository: https://github.com/joepie91/isohunt-grab + contributions_accepted: no + license: WTFPL / CC0 + decube: + category: finished + description: A quick tool for decoding HTML source that is encoded with the Ioncube HTML encoder. + repository: https://github.com/joepie91/main/blob/master/tools/decoding/decube.py + contributions_accepted: yes + license: WTFPL / CC0 + bayfilesfetch: + category: finished + notes: This may or may not still work. + description: A script for turning Bayfiles URLs into wget-able URLs. + repository: https://github.com/joepie91/main/blob/master/tools/downloading/bayfilesfetch.py + contributions_accepted: no + license: WTFPL / CC0 + minusfetch: + category: finished + notes: This may or may not still work. + description: A script for turning Min.us URLs into wget-able URLs. + repository: https://github.com/joepie91/main/blob/master/tools/downloading/minusfetch.py + contributions_accepted: no + license: WTFPL / CC0 + musicsearch.py: + category: finished + description: A commandline script for searching (and playing) music files via ex.fm. + repository: https://github.com/joepie91/main/blob/master/tools/downloading/musicsearch.py + contributions_accepted: yes + license: WTFPL / CC0 + resolv_dl: + category: finished + description: Resolves a URL from a file or video host using the `resolv` library, and downloads it. + repository: https://github.com/joepie91/main/blob/master/tools/downloading/resolv_dl.py + contributions_accepted: no + license: WTFPL / CC0 + resolv_vlc: + category: finished + description: Resolves a URL from a file or video host using the `resolv` library, and downloads it. + repository: https://github.com/joepie91/main/blob/master/tools/downloading/resolv_dl.py + contributions_accepted: no + license: WTFPL / CC0 + webfonts.py: + category: on_hold + notes: Currently quite broken. Fails to retrieve all types of font formats. + description: A script for downloading font files from Google Webfonts in various formats. + repository: https://github.com/joepie91/main/blob/master/tools/downloading/webfonts.py + contributions_accepted: yes + license: WTFPL / CC0 + catarc: + category: maintained + description: A tool to output (multiple) archives and compressed files to stdout, without the decompressed data ever touching the disk. + version: 1.1 + repository: https://github.com/joepie91/catarc + contributions_accepted: yes + license: WTFPL / CC0 + sha1rename: + category: finished + description: A script for renaming files according to their own SHA1 hash. + repository: https://github.com/joepie91/main/blob/master/tools/file-processing/sha1rename.py + contributions_accepted: no + license: WTFPL / CC0 + ipcheck: + category: finished + notes: Messy. The `dnsbl.txt` file is included in the parent folder. + description: A mass-DNSBL-checking IRC bot, for networks whose services package and IRCd do not have DNSBL functionality. Requires oper credentials. + repository: https://github.com/joepie91/main/blob/master/tools/irc/ipcheck.py + contributions_accepted: yes + license: WTFPL / CC0 + rakill: + category: finished + description: An IRC bot that can match all users on a network against a regular expression, and list, kill or gline them. Useful for dealing with IRC botfloods when the services package is lacking in moderation tools. Supports UnrealIRCd and InspIRCd (and possibly others). + repository: https://github.com/joepie91/main/blob/master/tools/irc/rakill.py + contributions_accepted: yes + license: WTFPL / CC0 + flickrgrab: + category: finished + notes: May or may not still work. + description: Script for mass-downloading a Flickr user. + repository: https://github.com/joepie91/main/blob/master/tools/scrapers/flickrgrab.py + contributions_accepted: yes + license: WTFPL / CC0 + speedtest.py: + category: unmaintained + notes: Never finished. Works for downloading, but not for uploading. Plenty of alternatives around. + description: A script for running a speedtest from your terminal. + repository: https://github.com/joepie91/main/blob/master/tools/server-management/speedtest.py + contributions_accepted: no + license: WTFPL / CC0 + BoxOnABudget: + category: on_hold + notes: Unlikely to ever be finished. Originally intended as a replacement for LowEndBox/LowEndTalk, but seems VPSBoard has that mostly covered now. + description: The forum and blog software for the (work-in-progress) BoxOnABudget site. + repository: https://github.com/joepie91/box + contributions_accepted: yes + license: WTFPL / CC0 + 4chandownloader: + category: unmaintained + notes: Probably broken. + description: A script to download all full-size images in a 4chan thread. + repository: https://github.com/joepie91/4chandownloader + contributions_accepted: no + license: WTFPL / CC0 + jamendoparser: + category: unmaintained + notes: Given the Jamendo API changes, it's very questionable whether this script still works or will keep working in the future. + description: A script that downloads the Jamendo database dump, and parses it into an SQLite database. + repository: https://github.com/joepie91/jamendoparser + contributions_accepted: no + license: WTFPL / CC0 + hypervm-migrate: + category: unmaintained + notes: Functional against the version of HyperVM at the date of last release (March 7, 2013). No guarantees, always backup your stuff. + description: A HyperVM mass migration script. + repository: https://github.com/joepie91/hypervm-migrate + contributions_accepted: no + license: WTFPL / CC0 + multiloggy: + category: maintained + notes: This is a fork of Sean B. Palmers' `loggy` bot. The original did not have support for more than one channel. + description: A public IRC logging bot, with multi-channel support. + repository: https://github.com/joepie91/multiloggy + contributions_accepted: yes + license: WTFPL / CC0 + tahoe-tools: + category: finished + description: Some miscellaneous tools for interacting with a Tahoe-LAFS storage grid. + repository: https://github.com/joepie91/tahoe-tools + contributions_accepted: yes + license: WTFPL / CC0 + nodecontrol: + category: unmaintained + notes: Superseded by Nexus and Cryto-Status. + description: Server deployment, control and monitoring application. + repository: https://github.com/joepie91/nodecontrol + contributions_accepted: yes + license: WTFPL / CC0 + Cryto WHOIS: + category: on_hold + notes: This turned out not to work well with lighttpd. MongoDB also turns out to be a bad choice. May be rewritten in the future. + description: A web-based public frontend for the `pythonwhois` library. + website: http://whois.cryto.net/ + repository: https://github.com/joepie91/crytowhois + contributions_accepted: yes + license: WTFPL / CC0 + multipaste: + category: unmaintained + notes: Messy, probably broken by now. + description: Quick-and-dirty script for pasting the same text to multiple pastebin services. + repository: https://github.com/joepie91/multipaste + contributions_accepted: yes + license: WTFPL / CC0 + Webshots Tools: + category: finished + notes: Webshots is no more. + description: Crawling tools for the ArchiveTeam Webshots archiving project. + repository: https://github.com/joepie91/webshots + contributions_accepted: no + license: WTFPL / CC0 + pyreactor: + category: on_hold + notes: Fate uncertain. May perhaps be updated to use ZeroMQ, but is likely to simply be abandoned. + description: A simple evented networking library for Python, designed for easy creation of custom protocols. + repository: https://github.com/joepie91/pyreactor + contributions_accepted: yes + license: WTFPL / CC0 + lighttpdparse: + category: finished + description: A simple script for getting the top statistics from one or more lighttpd access log files. + repository: https://github.com/joepie91/lighttpdparse + contributions_accepted: yes + license: WTFPL / CC0 + GMHost: + category: unmaintained + notes: Hosted service currently down. Low demand. + description: A simple Tahoe-LAFS based filehosting service. + website: http://gmhost.cryto.net/ + repository: https://github.com/joepie91/gmhost + contributions_accepted: yes + license: WTFPL / CC0 \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..98136df --- /dev/null +++ b/style.css @@ -0,0 +1,74 @@ +body { + font-family: sans-serif; } + body .wrapper { + width: 960px; + margin: 0px auto; } + body .category { + border-top: 2px solid silver; + padding-top: 8px; + margin-top: 40px; } + body .category p { + margin-bottom: 32px; } + body .category .project { + background: #f2f2f2; + /* Old browsers */ + background: -moz-linear-gradient(top, #f2f2f2 0%, #e0e0e0 100%); + /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f2f2f2), color-stop(100%, #e0e0e0)); + /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #f2f2f2 0%, #e0e0e0 100%); + /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #f2f2f2 0%, #e0e0e0 100%); + /* Opera 11.10+ */ + background: -ms-linear-gradient(top, #f2f2f2 0%, #e0e0e0 100%); + /* IE10+ */ + background: linear-gradient(to bottom, #f2f2f2 0%, #e0e0e0 100%); + /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f2f2f2', endColorstr='#e0e0e0',GradientType=0 ); + /* IE6-9 */ + box-shadow: 0px 1px 7px 1px #8f8f8f; + -webkit-box-shadow: 0px 1px 7px 1px #8f8f8f; + -moz-box-shadow: 0px 1px 7px 1px #8f8f8f; + -o-box-shadow: 0px 1px 7px 1px #8f8f8f; + -ms-box-shadow: 0px 1px 7px 1px #8f8f8f; + border-radius: 9px; + margin-bottom: 18px; + overflow: hidden; } + body .category .project .contents { + padding: 14px 18px; } + body .category .project h3 { + margin-top: 0px; + margin-bottom: 0px; + font-size: 24px; } + body .category .project p { + margin-bottom: 0px; } + body .category .project p.notes { + font-weight: bold; } + body .category .project p.notes i { + margin-right: 5px; } + body .category .project p.license { + color: #87888d; + font-size: 14px; + margin-top: 2px; } + body .category .project .top-bar { + float: right; + display: block; + padding: 8px 16px; + font-size: 18px; + text-decoration: none; + color: #2e2e2e; + border-bottom: 1px solid silver; + border-left: 1px solid silver; + border-top: 0px; + border-right: 0px; + background-color: transparent; } + body .category .project .top-bar:last-child { + border-bottom-left-radius: 7px; } + body .category .project .top-bar i { + margin-right: 5px; } + body .category .project .top-bar.contributions-yes { + color: #005200; } + body .category .project .top-bar.contributions-no { + color: #ac0000; } + +/*# sourceMappingURL=style.css.map */ \ No newline at end of file diff --git a/style.scss b/style.scss new file mode 100644 index 0000000..d158cfc --- /dev/null +++ b/style.scss @@ -0,0 +1,113 @@ +body +{ + font-family: sans-serif; + + .wrapper + { + width: 960px; + margin: 0px auto; + } + + .category + { + border-top: 2px solid silver; + padding-top: 8px; + margin-top: 40px; + + p + { + margin-bottom: 32px; + } + + .project + { + background: #f2f2f2; /* Old browsers */ + background: -moz-linear-gradient(top, #f2f2f2 0%, #e0e0e0 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f2f2f2), color-stop(100%,#e0e0e0)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #f2f2f2 0%,#e0e0e0 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #f2f2f2 0%,#e0e0e0 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(top, #f2f2f2 0%,#e0e0e0 100%); /* IE10+ */ + background: linear-gradient(to bottom, #f2f2f2 0%,#e0e0e0 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f2f2f2', endColorstr='#e0e0e0',GradientType=0 ); /* IE6-9 */ + + box-shadow: 0px 1px 7px 1px #8f8f8f; + -webkit-box-shadow: 0px 1px 7px 1px #8f8f8f; + -moz-box-shadow: 0px 1px 7px 1px #8f8f8f; + -o-box-shadow: 0px 1px 7px 1px #8f8f8f; + -ms-box-shadow: 0px 1px 7px 1px #8f8f8f; + + border-radius: 9px; + margin-bottom: 18px; + overflow: hidden; + + .contents + { + padding: 14px 18px; + } + + h3 + { + margin-top: 0px; + margin-bottom: 0px; + font-size: 24px; + } + + p + { + margin-bottom: 0px; + + &.notes + { + font-weight: bold; + + i + { + margin-right: 5px; + } + } + + &.license + { + color: rgb(135, 136, 141); + font-size: 14px; + margin-top: 2px; + } + } + + .top-bar + { + float: right; + display: block; + padding: 8px 16px; + font-size: 18px; + text-decoration: none; + color: #2e2e2e; + border-bottom: 1px solid silver; + border-left: 1px solid silver; + border-top: 0px; + border-right: 0px; + background-color: transparent; + + &:last-child + { + border-bottom-left-radius: 7px; + } + + i + { + margin-right: 5px; + } + + &.contributions-yes + { + color: rgb(0, 82, 0); + } + + &.contributions-no + { + color: rgb(172, 0, 0); + } + } + } + } +} \ No newline at end of file