1
0

smaller prog previews + self test

This commit is contained in:
Mike Schwörer 2018-01-27 14:21:34 +01:00
parent 88e04c4a87
commit a84a475008
Signed by: Mikescher
GPG Key ID: D3C7172E0A70F8CF
58 changed files with 521 additions and 54 deletions

1
www/data/binaries/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.zip

View File

@ -230,6 +230,8 @@ body {
background-color: #555; } background-color: #555; }
#headerdiv .tabrow .tab_active { #headerdiv .tabrow .tab_active {
background-color: #442222; } background-color: #442222; }
#headerdiv .tabrow .tab_admin {
background-color: #222244; }
#headerdiv .tabrow .tab_split { #headerdiv .tabrow .tab_split {
flex: auto; } flex: auto; }
#headerdiv .tabrow .tab_github { #headerdiv .tabrow .tab_github {
@ -1051,6 +1053,8 @@ html, body {
.keyvaluelist div { .keyvaluelist div {
display: flex; display: flex;
flex-direction: row; } flex-direction: row; }
.keyvaluelist div span {
align-self: center; }
.keyvaluelist div span:first-child { .keyvaluelist div span:first-child {
font-weight: bold; font-weight: bold;
min-width: 500px; } min-width: 500px; }
@ -1064,6 +1068,21 @@ html, body {
.kvl_300 div span:first-child { .kvl_300 div span:first-child {
min-width: 300px; } min-width: 300px; }
.consistency_result_ok, .consistency_result_warn, .consistency_result_err {
min-width: 400px;
border: 1px solid #888;
padding: 0 5px;
margin: 1px 0; }
.consistency_result_ok {
background: #0F0; }
.consistency_result_warn {
background: #FF0; }
.consistency_result_err {
background: #F00; }
/* 400px */ /* 400px */
#loginform div { #loginform div {
display: flex; display: flex;

View File

@ -48,6 +48,7 @@ body{background-color:#EEE;color:#CCC;font-family:serif}
#headerdiv .tabrow .tab{display:flex;justify-content:center;align-items:center;background-color:#222;color:#CCC;border-left:1px solid #000;border-right:1px solid #000;font-weight:bold;text-decoration:none;margin:0 0 0 20px;padding:2px 5px;min-width:64px;text-align:center;flex:initial} #headerdiv .tabrow .tab{display:flex;justify-content:center;align-items:center;background-color:#222;color:#CCC;border-left:1px solid #000;border-right:1px solid #000;font-weight:bold;text-decoration:none;margin:0 0 0 20px;padding:2px 5px;min-width:64px;text-align:center;flex:initial}
#headerdiv .tabrow .tab:hover{cursor:pointer;background-color:#555} #headerdiv .tabrow .tab:hover{cursor:pointer;background-color:#555}
#headerdiv .tabrow .tab_active{background-color:#422} #headerdiv .tabrow .tab_active{background-color:#422}
#headerdiv .tabrow .tab_admin{background-color:#224}
#headerdiv .tabrow .tab_split{flex:auto} #headerdiv .tabrow .tab_split{flex:auto}
#headerdiv .tabrow .tab_github{background-color:#4078c0;border-left:1px solid #111;border-right:0;color:black} #headerdiv .tabrow .tab_github{background-color:#4078c0;border-left:1px solid #111;border-right:0;color:black}
#headerdiv .tabrow .tab_github:hover{background-color:#c9510c;color:black} #headerdiv .tabrow .tab_github:hover{background-color:#c9510c;color:black}
@ -260,10 +261,15 @@ html,body{margin:0;padding:0;height:100%}
.egh_ajaxOutput{display:flex;box-sizing:border-box;width:100%;align-self:center;justify-self:center;margin-left:auto;margin-right:auto;resize:none;height:300px} .egh_ajaxOutput{display:flex;box-sizing:border-box;width:100%;align-self:center;justify-self:center;margin-left:auto;margin-right:auto;resize:none;height:300px}
.keyvaluelist{display:flex;flex-direction:column} .keyvaluelist{display:flex;flex-direction:column}
.keyvaluelist div{display:flex;flex-direction:row} .keyvaluelist div{display:flex;flex-direction:row}
.keyvaluelist div span{align-self:center}
.keyvaluelist div span:first-child{font-weight:bold;min-width:500px} .keyvaluelist div span:first-child{font-weight:bold;min-width:500px}
.kvl_100 div span:first-child{min-width:100px} .kvl_100 div span:first-child{min-width:100px}
.kvl_200 div span:first-child{min-width:200px} .kvl_200 div span:first-child{min-width:200px}
.kvl_300 div span:first-child{min-width:300px} .kvl_300 div span:first-child{min-width:300px}
.consistency_result_ok,.consistency_result_warn,.consistency_result_err{min-width:400px;border:1px solid #888;padding:0 5px;margin:1px 0}
.consistency_result_ok{background:#0F0}
.consistency_result_warn{background:#FF0}
.consistency_result_err{background:#F00}
#loginform div{display:flex;flex-direction:column} #loginform div{display:flex;flex-direction:column}
#loginform div button{margin:10px 0;padding:0} #loginform div button{margin:10px 0;padding:0}
.loginerror{display:flex;background:#f44;font-weight:bold;padding:0 5px;margin:5px 0 20px 0} .loginerror{display:flex;background:#f44;font-weight:bold;padding:0 5px;margin:5px 0 20px 0}

View File

@ -29,7 +29,7 @@
div { div {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
span {align-self: center;}
span:first-child { span:first-child {
font-weight: bold; font-weight: bold;
min-width: 500px; min-width: 500px;
@ -45,3 +45,13 @@
.kvl_100 div span:first-child { min-width: 100px; } .kvl_100 div span:first-child { min-width: 100px; }
.kvl_200 div span:first-child { min-width: 200px; } .kvl_200 div span:first-child { min-width: 200px; }
.kvl_300 div span:first-child { min-width: 300px; } .kvl_300 div span:first-child { min-width: 300px; }
.consistency_result_ok, .consistency_result_warn, .consistency_result_err {
min-width: 400px;
border: 1px solid #888;
padding: 0 5px;
margin: 1px 0;
}
.consistency_result_ok { background: #0F0; }
.consistency_result_warn { background: #FF0; }
.consistency_result_err { background: #F00; }

View File

@ -13,6 +13,7 @@ $COL_COMPLEXHOVER_BRD: black;
$COL_GITHUB: #4078C0; $COL_GITHUB: #4078C0;
$COL_HIGHLIGHT_RED: #442222; $COL_HIGHLIGHT_RED: #442222;
$COL_HIGHLIGHT_BLUE: #222244;
$FONT_HEADER: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; $FONT_HEADER: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif;
$FONT_CODE: Consolas, Monaco, "Courier New", Menlo, monospace; $FONT_CODE: Consolas, Monaco, "Courier New", Menlo, monospace;

View File

@ -53,6 +53,7 @@
} }
.tab_active { background-color: $COL_HIGHLIGHT_RED; } .tab_active { background-color: $COL_HIGHLIGHT_RED; }
.tab_admin { background-color: $COL_HIGHLIGHT_BLUE; }
.tab_split { .tab_split {
flex: auto; flex: auto;

4
www/data/dynamic/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*
!.gitignore
!.gitkeep
!.htaccess

View File

View File

@ -0,0 +1 @@
Deny from all

View File

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 95 KiB

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 133 KiB

View File

Before

Width:  |  Height:  |  Size: 276 KiB

After

Width:  |  Height:  |  Size: 276 KiB

View File

Before

Width:  |  Height:  |  Size: 348 KiB

After

Width:  |  Height:  |  Size: 348 KiB

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View File

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 131 KiB

View File

Before

Width:  |  Height:  |  Size: 198 KiB

After

Width:  |  Height:  |  Size: 198 KiB

View File

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 130 KiB

View File

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 194 KiB

View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

Before

Width:  |  Height:  |  Size: 262 KiB

After

Width:  |  Height:  |  Size: 262 KiB

View File

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

View File

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 164 KiB

View File

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 124 KiB

View File

@ -8,7 +8,7 @@
<a class="tab <?php if ($HEADER_ACTIVE === 'euler') echo 'tab_active'; ?>" href="/blog/1/Project_Euler_with_Befunge">Project Euler</a> <a class="tab <?php if ($HEADER_ACTIVE === 'euler') echo 'tab_active'; ?>" href="/blog/1/Project_Euler_with_Befunge">Project Euler</a>
<a class="tab <?php if ($HEADER_ACTIVE === 'blog') echo 'tab_active'; ?>" href="/blog">Blog</a> <a class="tab <?php if ($HEADER_ACTIVE === 'blog') echo 'tab_active'; ?>" href="/blog">Blog</a>
<a class="tab <?php if ($HEADER_ACTIVE === 'programs') echo 'tab_active'; ?>" href="/programs">Programs</a> <a class="tab <?php if ($HEADER_ACTIVE === 'programs') echo 'tab_active'; ?>" href="/programs">Programs</a>
<?php if (isLoggedInByCookie()): ?><a class="tab tab_active" href="/admin">Admin</a><?php endif; ?> <?php if (isLoggedInByCookie()): ?><a class="tab tab_admin" href="/admin">Admin</a><?php endif; ?>
<a class="tab <?php if ($HEADER_ACTIVE === 'about') echo 'tab_active'; ?>" href="/about">About</a> <a class="tab <?php if ($HEADER_ACTIVE === 'about') echo 'tab_active'; ?>" href="/about">About</a>
<div class="tab_split" ></div> <div class="tab_split" ></div>
<?php if (isLoggedInByCookie()): ?><a class="tab tab_logout" href="/logout">{Logout}</a><?php endif; ?> <?php if (isLoggedInByCookie()): ?><a class="tab tab_logout" href="/logout">{Logout}</a><?php endif; ?>

View File

@ -19,7 +19,7 @@
echo '<a href="' . $prog['url'] . '" class="programs_pnl_entry">' . "\n"; echo '<a href="' . $prog['url'] . '" class="programs_pnl_entry">' . "\n";
echo ' <div class="programs_pnl_img">' . "\n"; echo ' <div class="programs_pnl_img">' . "\n";
echo ' <img src="' . $prog['thumbnail_url'] . '" alt="Thumbnail ' . $prog['name'] . ' " />' . "\n"; echo ' <img src="' . $prog['preview_url'] . '" alt="Thumbnail ' . $prog['name'] . ' " />' . "\n";
echo ' </div>' . "\n"; echo ' </div>' . "\n";
echo ' <div class="programs_pnl_center">' . "\n"; echo ' <div class="programs_pnl_center">' . "\n";
echo htmlspecialchars($prog['name']) . "\n"; echo htmlspecialchars($prog['name']) . "\n";

View File

@ -37,8 +37,9 @@ $URL_RULES =
[ 'url' => ['api', 'statsping'], 'target' => 'pages/api_stats.php', 'options' => [ 'Name' => '%GET%', 'ClientID' => '%GET%', 'Version' => '%GET%', 'ProviderStr' => '%GET%', 'ProviderID' => '%GET%', 'NoteCount' => '%GET%', ], ], [ 'url' => ['api', 'statsping'], 'target' => 'pages/api_stats.php', 'options' => [ 'Name' => '%GET%', 'ClientID' => '%GET%', 'Version' => '%GET%', 'ProviderStr' => '%GET%', 'ProviderID' => '%GET%', 'NoteCount' => '%GET%', ], ],
[ 'url' => ['admin'], 'target' => 'pages/admin.php', 'options' => [ '_opt' => 'password'], ], [ 'url' => ['admin'], 'target' => 'pages/admin.php', 'options' => [ '_opt' => 'password'], ],
[ 'url' => ['admin', 'cmd', '?{cmd}'], 'target' => 'pages/admin_cmd.php', 'options' => [ '_opt' => 'password', 'cmd' => '%URL%'], ],
[ 'url' => ['admin', 'egh', '?{cmd}'], 'target' => 'pages/su_ajax.php', 'options' => [ 'suffix' => 'egh', 'cmd' => '%URL%', 'secret' => '%GET%' ], ], [ 'url' => ['admin', 'egh', '?{cmd}'], 'target' => 'pages/su_ajax.php', 'options' => [ 'suffix' => 'egh', 'cmd' => '%URL%', 'secret' => '%GET%' ], ],
[ 'url' => ['su_ajax', '?{cmd}'], 'target' => 'pages/su_ajax.php', 'options' => [ 'suffix' => '', 'cmd' => '%URL%', 'secret' => '%GET%' ], ], [ 'url' => ['su_ajax', '?{cmd}'], 'target' => 'pages/su_ajax.php', 'options' => [ 'suffix' => '', 'cmd' => '%URL%', 'secret' => '%GET%' ], ],
[ 'url' => ['su_ajax'], 'target' => 'pages/su_ajax.php', 'options' => [ 'suffix' => '', 'cmd' => '%GET%', 'secret' => '%GET%' ], ], [ 'url' => ['su_ajax'], 'target' => 'pages/su_ajax.php', 'options' => [ 'suffix' => '', 'cmd' => '%GET%', 'secret' => '%GET%' ], ],
@ -85,7 +86,7 @@ try {
$parse = parse_url($requri); $parse = parse_url($requri);
$path = strtolower(isset($parse['path']) ? $parse['path'] : ''); $path = isset($parse['path']) ? $parse['path'] : '';
$pathparts = preg_split('@/@', $path, NULL, PREG_SPLIT_NO_EMPTY); $pathparts = preg_split('@/@', $path, NULL, PREG_SPLIT_NO_EMPTY);
$partcount = count($pathparts); $partcount = count($pathparts);
@ -187,6 +188,5 @@ try {
//TODO better gh widget //TODO better gh widget
//TODO remove db table prefixes //TODO remove db table prefixes
//TODO euler insert+show 32bit | 64bit mode //TODO euler insert+show 32bit | 64bit mode
//TODO optimize image sizes for display/download (? - auto?)
//TODO send cache header (?) //TODO send cache header (?)
//TODO global uncached error logger -> send by mail //TODO global uncached error logger -> send by mail

View File

@ -182,3 +182,110 @@ function clearLoginCookie()
{ {
setcookie("mikescher_auth", "", time()+30); setcookie("mikescher_auth", "", time()+30);
} }
/**
* easy image resize function
* @author http://www.nimrodstech.com/php-image-resize/
* @param $file - file name to resize
* @param $string - The image data, as a string
* @param $width - new image width
* @param $height - new image height
* @param $proportional - keep image proportional, default is no
* @param $output - name of the new file (include path if needed)
* @param $quality - enter 1-100 (100 is best quality) default is 100
* @return boolean|resource
*/
function smart_resize_image($file, $string = null, $width = 0, $height = 0, $proportional = false, $output = 'file', $quality = 100
) {
if ( $height <= 0 && $width <= 0 ) return false;
if ( $file === null && $string === null ) return false;
# Setting defaults and meta
$info = $file !== null ? getimagesize($file) : getimagesizefromstring($string);
$image = '';
$final_width = 0;
$final_height = 0;
list($width_old, $height_old) = $info;
$cropHeight = $cropWidth = 0;
# Calculating proportionality
if ($proportional) {
if ($width == 0) $factor = $height/$height_old;
elseif ($height == 0) $factor = $width/$width_old;
else $factor = min( $width / $width_old, $height / $height_old );
$final_width = round( $width_old * $factor );
$final_height = round( $height_old * $factor );
}
else {
$final_width = ( $width <= 0 ) ? $width_old : $width;
$final_height = ( $height <= 0 ) ? $height_old : $height;
$widthX = $width_old / $width;
$heightX = $height_old / $height;
$x = min($widthX, $heightX);
$cropWidth = ($width_old - $width * $x) / 2;
$cropHeight = ($height_old - $height * $x) / 2;
}
# Loading image to memory according to type
switch ( $info[2] ) {
case IMAGETYPE_JPEG: $file !== null ? $image = imagecreatefromjpeg($file) : $image = imagecreatefromstring($string); break;
case IMAGETYPE_GIF: $file !== null ? $image = imagecreatefromgif($file) : $image = imagecreatefromstring($string); break;
case IMAGETYPE_PNG: $file !== null ? $image = imagecreatefrompng($file) : $image = imagecreatefromstring($string); break;
default: return false;
}
# This is the resizing/resampling/transparency-preserving magic
$image_resized = imagecreatetruecolor( $final_width, $final_height );
if ( ($info[2] == IMAGETYPE_GIF) || ($info[2] == IMAGETYPE_PNG) ) {
$transparency = imagecolortransparent($image);
$palletsize = imagecolorstotal($image);
if ($transparency >= 0 && $transparency < $palletsize) {
$transparent_color = imagecolorsforindex($image, $transparency);
$transparency = imagecolorallocate($image_resized, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
imagefill($image_resized, 0, 0, $transparency);
imagecolortransparent($image_resized, $transparency);
}
elseif ($info[2] == IMAGETYPE_PNG) {
imagealphablending($image_resized, false);
$color = imagecolorallocatealpha($image_resized, 0, 0, 0, 127);
imagefill($image_resized, 0, 0, $color);
imagesavealpha($image_resized, true);
}
}
imagecopyresampled($image_resized, $image, 0, 0, $cropWidth, $cropHeight, $final_width, $final_height, $width_old - 2 * $cropWidth, $height_old - 2 * $cropHeight);
# Preparing a method of providing result
switch ( strtolower($output) ) {
case 'browser':
$mime = image_type_to_mime_type($info[2]);
header("Content-type: $mime");
$output = NULL;
break;
case 'file':
$output = $file;
break;
case 'return':
return $image_resized;
break;
default:
break;
}
# Writing image according to type to the output destination and image quality
switch ( $info[2] ) {
case IMAGETYPE_GIF: imagegif($image_resized, $output); break;
case IMAGETYPE_JPEG: imagejpeg($image_resized, $output, $quality); break;
case IMAGETYPE_PNG:
$quality = 9 - (int)((0.9*$quality)/10.0);
imagepng($image_resized, $output, $quality);
break;
default: return false;
}
return true;
}

View File

@ -18,6 +18,8 @@ class Blog
$d['canonical'] = "https://www.mikescher.com" . $d['url']; $d['canonical'] = "https://www.mikescher.com" . $d['url'];
$d['file_fragment'] = __DIR__ . '/../statics/blog/' . $d['fragment'];
return $d; return $d;
} }
@ -38,7 +40,40 @@ class Blog
public static function getPostFragment($post) public static function getPostFragment($post)
{ {
return file_get_contents( __DIR__ . '/../statics/blog/' . $post['fragment']); return file_get_contents($post['file_fragment']);
}
public static function checkConsistency()
{
$keys = [];
foreach (self::listAll() as $post)
{
if (in_array($post['id'], $keys)) return ['result'=>'err', 'message' => 'Duplicate key ' . $post['id']];
$keys []= $post['id'];
if ($post['cat'] !== 'log' && $post['cat'] !== 'blog') return ['result'=>'err', 'message' => 'Unknown cat ' . $post['cat']];
if ($post['type'] === 'markdown') {
if (!file_exists($post['file_fragment'])) return ['result'=>'err', 'message' => 'Fragment not found ' . $post['fragment']];
} else if ($post['type'] === 'plain') {
if (!file_exists($post['file_fragment'])) return ['result'=>'err', 'message' => 'Fragment not found ' . $post['fragment']];
} else if ($post['type'] === 'euler') {
// aok
} else {
return ['result'=>'err', 'message' => 'Unknown type ' . $post['type']];
}
}
return ['result'=>'ok', 'message' => ''];
} }
} }

View File

@ -67,5 +67,29 @@ class Euler
return 4; return 4;
} }
public static function checkConsistency()
{
$warn = null;
$numbers = [];
$realname = [];
foreach (self::listAll() as $ep)
{
if (in_array($ep['number'], $numbers)) return ['result'=>'err', 'message' => 'Duplicate number ' . $ep['number']];
$numbers []= $ep['number'];
if (in_array($ep['title'], $realname)) return ['result'=>'err', 'message' => 'Duplicate title ' . $ep['title']];
$realname []= $ep['title'];
if (!file_exists($ep['file_description'])) return ['result'=>'err', 'message' => 'file_description not found ' . $ep['file_description']];
if (!file_exists($ep['file_code'])) return ['result'=>'err', 'message' => 'file_code not found ' . $ep['file_code']];
if (!file_exists($ep['file_explanation'])) return ['result'=>'err', 'message' => 'file_explanation not found ' . $ep['file_explanation']];
}
if ($warn != null) return $warn;
return ['result'=>'ok', 'message' => ''];
}
} }

View File

@ -26,4 +26,26 @@ class MikescherGitGraph
return $v; return $v;
} }
public static function getPathRenderedData()
{
return __DIR__ . '/../dynamic/egh.html';
}
public static function includeRender()
{
if (file_exists(__DIR__ . '/../dynamic/egh.html'))
include __DIR__ . '/../dynamic/egh.html';
}
public static function checkConsistency()
{
$p = self::getPathRenderedData();
if (!file($p)) return ['result'=>'err', 'message' => 'Rendered data not found'];
if (filemtime($p) < time()-(3*7*24*60*60)) return ['result'=>'warn', 'message' => 'Rendered data is older than 3 weeks'];
return ['result'=>'ok', 'message' => ''];
}
} }

View File

@ -1,7 +1,11 @@
<?php if(count(get_included_files()) ==1) exit("Direct access not permitted."); <?php if(count(get_included_files()) ==1) exit("Direct access not permitted.");
require_once __DIR__ . '/base.php';
class Programs class Programs
{ {
const PROG_LANGS = [ 'Java', 'C#', 'Delphi', 'PHP', 'C++' ];
const URL_ORDER = const URL_ORDER =
[ [
'github', 'github',
@ -29,8 +33,14 @@ class Programs
public static function readSingle($a) public static function readSingle($a)
{ {
$a['thumbnail_url'] = '/data/images/program_thumbnails/' . $a['internal_name'] . '.png'; $a['mainimage_url'] = '/data/images/program_img/' . $a['internal_name'] . '.png';
$a['mainimage_path'] = __DIR__ . '/../data/images/program_img/' . $a['internal_name'] . '.png';
$a['preview_url'] = '/data/dynamic/progprev_' . $a['internal_name'] . '.png';
$a['preview_path'] = __DIR__ . '/../data/dynamic/progprev_' . $a['internal_name'] . '.png';
$a['file_longdescription'] = (__DIR__ . '/../statics/programs/' . $a['internal_name'] . '_description.md'); $a['file_longdescription'] = (__DIR__ . '/../statics/programs/' . $a['internal_name'] . '_description.md');
$a['url'] = '/programs/view/' . $a['internal_name']; $a['url'] = '/programs/view/' . $a['internal_name'];
return $a; return $a;
@ -73,6 +83,12 @@ class Programs
public static function urlComparator($a, $b) public static function urlComparator($a, $b)
{ {
$na = 0;
$nb = 0;
if (strpos($a, '#') !== FALSE) { $na = intval(explode('#', $a)[1]); $a=explode('#', $a)[0]; }
if (strpos($b, '#') !== FALSE) { $nb = intval(explode('#', $b)[1]); $b=explode('#', $b)[0]; }
$ia = array_search($a, Programs::URL_ORDER); $ia = array_search($a, Programs::URL_ORDER);
$ib = array_search($b, Programs::URL_ORDER); $ib = array_search($b, Programs::URL_ORDER);
@ -80,18 +96,153 @@ class Programs
if ($ia === false && $ib !== false) return +1; // sort [IA | IB] if ($ia === false && $ib !== false) return +1; // sort [IA | IB]
if ($ia !== false && $ib === false) return -1; // sort [IB | IA] if ($ia !== false && $ib === false) return -1; // sort [IB | IA]
if ($ia === $ib) return ($na < $nb) ? -1 : +1;
return ($ia < $ib) ? -1 : +1; return ($ia < $ib) ? -1 : +1;
} }
public static function sortUrls($urls) public static function getURLs($prog)
{ {
$urls = $prog['urls'];
uksort($urls, 'self::urlComparator'); uksort($urls, 'self::urlComparator');
return $urls;
$result = [];
foreach ($urls as $fulltype => $urldata)
{
$type = $fulltype;
if (strpos($fulltype, '#') !== FALSE) $type=explode('#', $fulltype)[0];
$caption = '?';
$css = '?';
$svg = '?';
$direct = false;
if ($type === 'download') { $caption = 'Download'; $css = 'prgv_dl_download'; $svg = 'download'; }
if ($type === 'github') { $caption = 'Github'; $css = 'prgv_dl_github'; $svg = 'github'; }
if ($type === 'homepage') { $caption = 'Homepage'; $css = 'prgv_dl_homepage'; $svg = 'home'; }
if ($type === 'wiki') { $caption = 'Wiki'; $css = 'prgv_dl_wiki'; $svg = 'wiki'; }
if ($type === 'playstore') { $caption = 'Google Playstore'; $css = 'prgv_dl_playstore'; $svg = 'playstore'; }
if ($type === 'amazonappstore') { $caption = 'Amazon Appstore'; $css = 'prgv_dl_amznstore'; $svg = 'amazon'; }
if ($type === 'windowsstore') { $caption = 'Microsoft Store'; $css = 'prgv_dl_winstore'; $svg = 'windows'; }
if ($type === 'itunesstore') { $caption = 'App Store'; $css = 'prgv_dl_appstore'; $svg = 'apple'; }
if ($type === 'sourceforge') { $caption = 'Sourceforge'; $css = 'prgv_dl_sourceforge'; $svg = 'sourceforge'; }
if ($type === 'alternativeto') { $caption = 'AlternativeTo'; $css = 'prgv_dl_alternativeto'; $svg = 'alternativeto'; }
if (is_array($urldata))
{
$url = $urldata['url'];
if (isset($urldata['caption'])) $caption = $urldata['caption'];
if (isset($urldata['css'])) $css = $urldata['css'];
if (isset($urldata['svg'])) $svg = $urldata['svg'];
}
else
{
$url = $urldata;
}
if ($url === 'direct')
{
$direct = true;
$url = Programs::getDirectDownloadURL($prog);
}
$result []=
[
'type' => $type,
'caption' => $caption,
'svg' => $svg,
'href' => $url,
'css' => $css,
'isdirect' => $direct,
];
}
return $result;
} }
public static function getLicenseUrl($license) public static function getLicenseUrl($license)
{ {
return self::LICENSES[$license]; return self::LICENSES[$license];
} }
public static function getDirectDownloadURL($prog)
{
return '/data/binaries/'.$prog['internal_name'].'.zip';
}
public static function getDirectDownloadPath($prog)
{
return (__DIR__ . '/../data/binaries/'.$prog['internal_name'].'.zip');
}
public static function checkConsistency()
{
$warn = null;
$intname = [];
$realname = [];
foreach (self::listAll() as $prog)
{
if (in_array($prog['internal_name'], $intname)) return ['result'=>'err', 'message' => 'Duplicate internal_name ' . $prog['name']];
$intname []= $prog['internal_name'];
if ($prog['internal_name_alt'] !== null)
{
if (in_array($prog['internal_name_alt'], $intname)) return ['result'=>'err', 'message' => 'Duplicate internal_name ' . $prog['name']];
$intname []= $prog['internal_name_alt'];
}
if (in_array($prog['name'], $realname)) return ['result'=>'err', 'message' => 'Duplicate name ' . $prog['name']];
$realname []= $prog['name'];
if (strpos($prog['internal_name'], ' ') !== FALSE) return ['result'=>'err', 'message' => 'Internal name contains spaces ' . $prog['name']];
foreach (explode('|', $prog['ui_language']) as $lang) if (convertLanguageToFlag($lang) === null) return ['result'=>'err', 'message' => 'Unknown ui-lang ' . $prog['name']];;
if (!in_array($prog['prog_language'], self::PROG_LANGS)) return ['result'=>'err', 'message' => 'Unknown prog-lang ' . $prog['name']];
if (strlen($prog['short_description'])> 128) $warn = ['result'=>'warn', 'message' => 'short_description too long ' . $prog['name']];
if ($prog['license'] !== null && !array_key_exists($prog['license'], self::LICENSES)) return ['result'=>'err', 'message' => 'Unknown license ' . $prog['name']];
$isdl = false;
foreach (self::getURLs($prog) as $xurl)
{
if (!in_array($xurl['type'], self::URL_ORDER)) return ['result'=>'err', 'message' => 'Unknown url ' . $xurl['type']];
if ($xurl['type']==='download' && $xurl['isdirect'] && !file_exists(self::getDirectDownloadPath($prog))) return ['result'=>'err', 'message' => 'Direct download not found ' . $prog['name']];
if ($xurl['type']==='download' || $xurl['type']==='playstore' || $xurl['type']==='itunesstore') $isdl = true;
}
if (!$isdl) return ['result'=>'err', 'message' => 'No download link ' . $prog['name']];
if (!file_exists($prog['mainimage_path'])) return ['result'=>'err', 'message' => 'Image not found ' . $prog['name']];
if (!file_exists($prog['file_longdescription'])) return ['result'=>'err', 'message' => 'Description not found ' . $prog['name']];
}
if ($warn != null) return $warn;
return ['result'=>'ok', 'message' => ''];
}
public static function checkThumbnails()
{
foreach (self::listAll() as $prog)
{
if (!file_exists($prog['preview_path'])) return ['result'=>'err', 'message' => 'Preview not found ' . $prog['name']];
}
return ['result'=>'ok', 'message' => ''];
}
public static function createPreview($prog)
{
$src = $prog['mainimage_path'];
$dst = $prog['preview_path'];
smart_resize_image($src , null, 250, 0, true, $dst, 100);
}
} }

View File

@ -2,6 +2,7 @@
<html lang="en"> <html lang="en">
<?php <?php
require_once (__DIR__ . '/../internals/base.php'); require_once (__DIR__ . '/../internals/base.php');
require_once (__DIR__ . '/../internals/mikeschergitgraph.php');
global $OPTIONS; global $OPTIONS;
?> ?>
<head> <head>
@ -46,7 +47,7 @@ global $OPTIONS;
<div class="bc_data about_egh_container"> <div class="bc_data about_egh_container">
<?php if (file_exists(__DIR__ . '/../dynamic/egh.html')) include __DIR__ . '/../dynamic/egh.html' ?> <?php MikescherGitGraph::includeRender(); ?>
</div> </div>

View File

@ -4,13 +4,33 @@
require_once (__DIR__ . '/../internals/base.php'); require_once (__DIR__ . '/../internals/base.php');
require_once (__DIR__ . '/../internals/highscores.php'); require_once (__DIR__ . '/../internals/highscores.php');
require_once (__DIR__ . '/../internals/alephnoteStatistics.php'); require_once (__DIR__ . '/../internals/alephnoteStatistics.php');
require_once (__DIR__ . '/../internals/blog.php');
require_once (__DIR__ . '/../internals/euler.php');
require_once (__DIR__ . '/../internals/highscores.php');
require_once (__DIR__ . '/../internals/mikeschergitgraph.php');
require_once (__DIR__ . '/../internals/programs.php');
Database::connect(); Database::connect();
$consistency_blog = Blog::checkConsistency();
$consistency_prog = Programs::checkConsistency();
$consistency_euler = Euler::checkConsistency();
$consistency_egh = MikescherGitGraph::checkConsistency();
$consistency_progimg = Programs::checkThumbnails();
?>
<?php
function dumpConsistency($c) {
if ($c['result']==='ok') echo "<span class='consistency_result_ok'>OK</span>";
else if ($c['result']==='warn') echo "<span class='consistency_result_warn'>".$c['message']."</span>";
else echo "<span class='consistency_result_err'>".$c['message']."</span>";
}
?> ?>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Mikescher.com - About</title> <title>Mikescher.com - Admin</title>
<link rel="icon" type="image/png" href="/data/images/favicon.png"/> <link rel="icon" type="image/png" href="/data/images/favicon.png"/>
<link rel="canonical" href="https://www.mikescher.com/about"/> <link rel="canonical" href="https://www.mikescher.com/about"/>
<?php printCSS(); ?> <?php printCSS(); ?>
@ -39,7 +59,27 @@ Database::connect();
<div><span>Date:</span> <span><?php echo exec('git log -1 --format=%cd'); ?></span></div> <div><span>Date:</span> <span><?php echo exec('git log -1 --format=%cd'); ?></span></div>
<div><span>Message:</span><span><?php echo nl2br(trim(exec('git log -1'))); ?></span></div> <div><span>Message:</span><span><?php echo nl2br(trim(exec('git log -1'))); ?></span></div>
</div> </div>
</div>
<!------------------------------------------>
<div class="boxedcontent">
<div class="bc_header">Self test</div>
<div class="bc_data">
<div class="keyvaluelist kvl_200">
<div><span>Program thumbnails:</span> <?php dumpConsistency($consistency_progimg); ?></div>
<div><span>ExtendedGitGraph:</span> <?php dumpConsistency($consistency_egh); ?></div>
<div><span>Book thumbnails:</span> <span>?</span></div>
<div><span>Blog data:</span> <?php dumpConsistency($consistency_blog); ?></div>
<div><span>Euler data:</span> <?php dumpConsistency($consistency_euler); ?></div>
<div><span>Programs data:</span> <?php dumpConsistency($consistency_prog); ?></div>
</div>
<br/>
<a class="button" href="/admin/cmd/createProgramThumbnails">Update Program Thumbnails</a>
<a class="button" href="/admin/cmd/createBookThumbnails">Update Book Thumbnails</a>
</div>
</div> </div>
<!------------------------------------------> <!------------------------------------------>

43
www/pages/admin_cmd.php Normal file
View File

@ -0,0 +1,43 @@
<?php
global $OPTIONS;
require_once (__DIR__ . '/../internals/base.php');
require_once (__DIR__ . '/../internals/programs.php');
$cmd = $OPTIONS['cmd'];
if ($cmd === 'createProgramThumbnails')
{
echo '<!DOCTYPE html>';
echo '<html lang="en">';
echo '<head>';
echo '<meta charset="utf-8">';
echo '<title>Mikescher.com - AdminExec</title>';
echo '<link rel="icon" type="image/png" href="/data/images/favicon.png"/>';
echo '<link rel="canonical" href="https://www.mikescher.com/logout"/>';
echo '<meta http-equiv="refresh" content="3; url=/admin; ?>" />';
echo '</head>';
echo '<body>';
foreach (Programs::listAll() as $prog)
{
echo 'Create preview for ' . $prog['name'] . '<br/>' . "\n";
Programs::createPreview($prog);
}
echo 'Finished.' . '<br/>' . "\n";
echo '<script>setTimeout(function () { window.location.href = "/admin"; }, 3000);</script>';
echo '</body>';
echo '</html>';
exit;
}
if ($cmd === 'createBookThumbnails')
{
//TODO
exit;
}
die('Wrong command.');

View File

@ -38,7 +38,7 @@ $allprograms = Programs::listAllNewestFirst($filter);
echo '<a class="prgl_elem" href="'.$prog['url'].'">'; echo '<a class="prgl_elem" href="'.$prog['url'].'">';
echo ' <div class="prgl_elem_left">'; echo ' <div class="prgl_elem_left">';
echo ' <img src="' . $prog['thumbnail_url'] . '" alt="Thumbnail ' . $prog['name'] . '" />'; echo ' <img src="' . $prog['preview_url'] . '" alt="Thumbnail ' . $prog['name'] . '" />';
echo ' </div>'; echo ' </div>';
echo ' <div class="prgl_elem_right">'; echo ' <div class="prgl_elem_right">';
echo ' <div class="prgl_elem_title">' . htmlspecialchars($prog['name']) . '</div>'; echo ' <div class="prgl_elem_title">' . htmlspecialchars($prog['name']) . '</div>';

View File

@ -34,7 +34,7 @@ if ($prog === NULL) httpError(404, 'Program not found');
<div class="contentheader" id="prgv_header"><h1><?php echo htmlspecialchars($prog['name']); ?></h1><hr/></div> <div class="contentheader" id="prgv_header"><h1><?php echo htmlspecialchars($prog['name']); ?></h1><hr/></div>
<div class="prgv_top"> <div class="prgv_top">
<div class="prgv_left"><img src="<?php echo $prog['thumbnail_url']; ?>" alt="Thumbnail (<?php echo $prog['name'] ?>)" /></div> <div class="prgv_left"><img src="<?php echo $prog['mainimage_url']; ?>" alt="Thumbnail (<?php echo $prog['name'] ?>)" /></div>
<div class="prgv_right"> <div class="prgv_right">
<div class="prgv_right_key" style="grid-row:1">Name:</div> <div class="prgv_right_key" style="grid-row:1">Name:</div>
<div class="prgv_right_value" style="grid-row:1"><a href="<?php echo $prog['url']; ?>"><?php echo htmlspecialchars($prog['name']) ?></a></div> <div class="prgv_right_value" style="grid-row:1"><a href="<?php echo $prog['url']; ?>"><?php echo htmlspecialchars($prog['name']) ?></a></div>
@ -55,20 +55,14 @@ if ($prog === NULL) httpError(404, 'Program not found');
<div class="prgv_right_comb" style="grid-row:6"> <div class="prgv_right_comb" style="grid-row:6">
<?php <?php
foreach (Programs::sortUrls($prog['urls']) as $type => $url) foreach (Programs::getURLs($prog) as $xurl)
{ {
if ($type === 'download' && $url === 'direkt') $url = '/data/binaries/'.$prog['internal_name'].'.zip'; echo '<a class="iconbutton '.$xurl['css'].'" href="'.$xurl['href'].'">';
echo '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">';
if ($type === 'download') echo '<a class="iconbutton prgv_dl_download" href="'.$url.'"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><use xlink:href="/data/images/icons.svg#download" /></svg><span>Download</span></a>'; echo '<use xlink:href="/data/images/icons.svg#'.$xurl['svg'].'"/>';
if ($type === 'github') echo '<a class="iconbutton prgv_dl_github" href="'.$url.'"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><use xlink:href="/data/images/icons.svg#github" /></svg><span>Github</span></a>'; echo '</svg>';
if ($type === 'homepage') echo '<a class="iconbutton prgv_dl_homepage" href="'.$url.'"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><use xlink:href="/data/images/icons.svg#home" /></svg><span>Homepage</span></a>'; echo '<span>'.$xurl['caption'].'</span>';
if ($type === 'wiki') echo '<a class="iconbutton prgv_dl_wiki" href="'.$url.'"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><use xlink:href="/data/images/icons.svg#wiki" /></svg><span>Wiki</span></a>'; echo '</a>';
if ($type === 'playstore') echo '<a class="iconbutton prgv_dl_playstore" href="'.$url.'"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><use xlink:href="/data/images/icons.svg#playstore" /></svg><span>Google Playstore</span></a>';
if ($type === 'amazonappstore') echo '<a class="iconbutton prgv_dl_amznstore" href="'.$url.'"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><use xlink:href="/data/images/icons.svg#amazon" /></svg><span>Amazon Appstore</span></a>';
if ($type === 'windowsstore') echo '<a class="iconbutton prgv_dl_winstore" href="'.$url.'"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><use xlink:href="/data/images/icons.svg#windows" /></svg><span>Microsoft Store</span></a>';
if ($type === 'itunesstore') echo '<a class="iconbutton prgv_dl_appstore" href="'.$url.'"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><use xlink:href="/data/images/icons.svg#apple" /></svg><span>App Store</span></a>';
if ($type === 'sourceforge') echo '<a class="iconbutton prgv_dl_sourceforge" href="'.$url.'"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><use xlink:href="/data/images/icons.svg#sourceforge" /></svg><span>Sourceforge</span></a>';
if ($type === 'alternativeto') echo '<a class="iconbutton prgv_dl_alternativeto" href="'.$url.'"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><use xlink:href="/data/images/icons.svg#alternativeto"/></svg><span>AlternativeTo</span></a>';
} }
?> ?>
</div> </div>

View File

@ -15,7 +15,7 @@ return
'license' => 'GPL-3.0', 'license' => 'GPL-3.0',
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'https://github.com/Mikescher/AbsCanvas/releases',
'github' => 'https://github.com/Mikescher/AbsCanvas', 'github' => 'https://github.com/Mikescher/AbsCanvas',
], ],
], ],
@ -34,7 +34,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -52,7 +52,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -72,6 +72,12 @@ return
[ [
'github' => 'https://github.com/Mikescher/BefunUtils', 'github' => 'https://github.com/Mikescher/BefunUtils',
'wiki' => 'https://github.com/Mikescher/BefunUtils/wiki', 'wiki' => 'https://github.com/Mikescher/BefunUtils/wiki',
'download#1' => ['caption'=>'BefunExec', 'url'=>'https://ci.appveyor.com/project/Mikescher/BefunExec/build/artifacts' ],
'download#2' => ['caption'=>'BefunGen', 'url'=>'https://ci.appveyor.com/project/Mikescher/BefunGen/build/artifacts' ],
'download#3' => ['caption'=>'BefunWrite', 'url'=>'https://ci.appveyor.com/project/Mikescher/BefunWrite/build/artifacts'],
'download#4' => ['caption'=>'BefunRep', 'url'=>'https://ci.appveyor.com/project/Mikescher/BefunRep/build/artifacts' ],
'download#5' => ['caption'=>'BefunRun', 'url'=>'https://ci.appveyor.com/project/Mikescher/BefunRun/build/artifacts' ],
'download#6' => ['caption'=>'BefunDebug', 'url'=>'https://ci.appveyor.com/project/Mikescher/BefunDebug/build/artifacts'],
], ],
], ],
@ -89,7 +95,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -107,7 +113,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
'homepage' => 'http://borderlinedefense.99k.org/', 'homepage' => 'http://borderlinedefense.99k.org/',
], ],
], ],
@ -126,7 +132,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -144,7 +150,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -162,7 +168,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -198,7 +204,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -216,7 +222,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -253,7 +259,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -271,7 +277,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
'sourceforge' => 'http://sourceforge.net/projects/jcircuits/', 'sourceforge' => 'http://sourceforge.net/projects/jcircuits/',
], ],
], ],
@ -329,7 +335,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
//TODO url 'download' => 'direct',
], ],
], ],
@ -347,7 +353,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -365,7 +371,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -383,7 +389,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -420,7 +426,7 @@ return
'license' => 'Unlicense', 'license' => 'Unlicense',
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'https://github.com/Mikescher/Serpilicum/releases',
'github' => 'https://github.com/Mikescher/Serpilicum', 'github' => 'https://github.com/Mikescher/Serpilicum',
], ],
], ],
@ -440,6 +446,7 @@ return
'urls' => 'urls' =>
[ [
'github' => 'https://github.com/Mikescher/SharkSim', 'github' => 'https://github.com/Mikescher/SharkSim',
'download' => 'https://github.com/Mikescher/SharkSim/releases',
], ],
], ],
@ -457,7 +464,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -475,7 +482,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -493,7 +500,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'https://github.com/Mikescher/SuperBitBros/releases',
'github' => 'https://github.com/Mikescher/SuperBitBros', 'github' => 'https://github.com/Mikescher/SuperBitBros',
], ],
], ],
@ -512,7 +519,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],
@ -530,7 +537,7 @@ return
'license' => null, 'license' => null,
'urls' => 'urls' =>
[ [
'download' => 'direkt', 'download' => 'direct',
], ],
], ],