diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index 9546bad..0000000 --- a/.drone.yml +++ /dev/null @@ -1,6 +0,0 @@ -pipeline: - build: - image: j1mc/docker-zola - commands: - - zola build - diff --git a/.garbage b/.garbage deleted file mode 100644 index e69de29..0000000 diff --git a/.gitignore b/.gitignore index a48cf0d..9ca7f2b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -public +/public +/old +/resources diff --git a/archetypes/default.md b/archetypes/default.md new file mode 100644 index 0000000..00e77bd --- /dev/null +++ b/archetypes/default.md @@ -0,0 +1,6 @@ +--- +title: "{{ replace .Name "-" " " | title }}" +date: {{ .Date }} +draft: true +--- + diff --git a/sass/_content.scss b/assets/sass/_content.scss similarity index 97% rename from sass/_content.scss rename to assets/sass/_content.scss index c42ab83..a65d6ca 100644 --- a/sass/_content.scss +++ b/assets/sass/_content.scss @@ -73,13 +73,6 @@ blockquote { } } -pre { - padding: 5px; - overflow-x: auto; - font-family: $monofont; - font-size: 0.9em; -} - code { font-size: 1.2em; padding: 3px; @@ -87,3 +80,11 @@ code { color: #cccccc; border-radius: 5px; } + +pre > code { + display: block; + padding: 5px; + overflow-x: auto; + font-family: $monofont; + font-size: 0.9em; +} diff --git a/sass/_syntax.scss b/assets/sass/_syntax.scss similarity index 99% rename from sass/_syntax.scss rename to assets/sass/_syntax.scss index e282020..f1aa7b2 100644 --- a/sass/_syntax.scss +++ b/assets/sass/_syntax.scss @@ -67,4 +67,4 @@ pre.highlight { background-color: #444444; color: #cccccc } .highlight .vc { color: #569cd6 } /* Name.Variable.Class */ .highlight .vg { color: #00cdcd } /* Name.Variable.Global */ .highlight .vi { color: #00cdcd } /* Name.Variable.Instance */ -.highlight .il { color: #b5cea8 } /* Literal.Number.Integer.Long */ \ No newline at end of file +.highlight .il { color: #b5cea8 } /* Literal.Number.Integer.Long */ diff --git a/sass/main.scss b/assets/sass/main.scss similarity index 93% rename from sass/main.scss rename to assets/sass/main.scss index 960ac17..49db4dc 100644 --- a/sass/main.scss +++ b/assets/sass/main.scss @@ -11,7 +11,6 @@ $monofont: "Roboto Mono", "Roboto Mono for Powerline", "Inconsolata", "Consolas" $small-text-color: lighten($text-color, 15%); $link-color: royalblue; @import "content"; - @import "graph"; } @media (prefers-color-scheme: dark) { @@ -20,5 +19,4 @@ $monofont: "Roboto Mono", "Roboto Mono for Powerline", "Inconsolata", "Consolas" $small-text-color: darken($text-color, 15%); $link-color: lightskyblue; @import "content"; - @import "graph"; } diff --git a/config.toml b/config.toml index 9ec5548..ff77348 100644 --- a/config.toml +++ b/config.toml @@ -1,22 +1,4 @@ +baseURL = "http://example.org/" +languageCode = "en-us" title = "michael's blog" -base_url = "https://iptq.io" - -compile_sass = true -highlight_code = true -generate_rss = true - -taxonomies = [ - { name = "tags", rss = true } -] - -[external_renderers] -dot = "set -e; echo -n '

'; dot -Tsvg | tail -n +4; echo '

'" - -[extra] -nav_links = [ - { url = "/", text = "home" }, - { url = "/pages/about", text = "about" }, - { url = "/pages/projects", text = "projects" }, - { url = "/setup", text = "setup" }, - { url = "/pages", text = "all pages" }, -] +enableGitInfo = true diff --git a/content/_index.md b/content/_index.md index c9d9014..d68db62 100644 --- a/content/_index.md +++ b/content/_index.md @@ -1,11 +1,8 @@ +++ -title = "home" -template = "blog.html" -page_template = "post.html" +layout = "home" -insert_anchor_links = "left" -sort_by = "date" - -[extra] -include_posts = true +[cascade] +type = "generic" +++ + +hello diff --git a/content/about/_index.md b/content/about/_index.md new file mode 100644 index 0000000..f2d4c89 --- /dev/null +++ b/content/about/_index.md @@ -0,0 +1,23 @@ ++++ +title = "about" ++++ + +Hi there! I'm a software enthusiast who recently graduated with a Computer +Science degree from the University of Minnesota. I've been doing web +development for a long time and now I'm looking into security, programming +language development, and software development! + +In an effort to rely on less services, I started doing a lot of self-hosting +and rewriting of software. Check out some of the projects I'm doing over on my +public [Gitea][2]! + +If you want my resume, contact me through one of these means: + +## contact + +- Email: (I sign all my Git commits with this email) +- PGP Key: [hosted on Keybase][1] +- IRC: michael on acm.umn.edu + +[1]: https://keybase.io/michaelz/pgp_keys.asc?fingerprint=925ecc02890d5cdae26180d4bda47a31a3c8ee6b +[2]: https://git.mzhang.io/explore diff --git a/content/enterprise/2020-02-11-prototype/helloworld.js b/content/enterprise/2020-02-11-prototype/helloworld.js deleted file mode 100644 index 5e8346e..0000000 --- a/content/enterprise/2020-02-11-prototype/helloworld.js +++ /dev/null @@ -1,639 +0,0 @@ -"use strict"; - -if( typeof Rust === "undefined" ) { - var Rust = {}; -} - -(function( root, factory ) { - if( typeof define === "function" && define.amd ) { - define( [], factory ); - } else if( typeof module === "object" && module.exports ) { - module.exports = factory(); - } else { - Rust.helloworld = factory(); - } -}( this, function() { - return (function( module_factory ) { - var instance = module_factory(); - - if( typeof process === "object" && typeof process.versions === "object" && typeof process.versions.node === "string" ) { - var fs = require( "fs" ); - var path = require( "path" ); - var wasm_path = path.join( __dirname, "helloworld.wasm" ); - var buffer = fs.readFileSync( wasm_path ); - var mod = new WebAssembly.Module( buffer ); - var wasm_instance = new WebAssembly.Instance( mod, instance.imports ); - return instance.initialize( wasm_instance ); - } else { - var file = fetch( "helloworld.wasm", {credentials: "same-origin"} ); - - var wasm_instance = ( typeof WebAssembly.instantiateStreaming === "function" - ? WebAssembly.instantiateStreaming( file, instance.imports ) - .then( function( result ) { return result.instance; } ) - - : file - .then( function( response ) { return response.arrayBuffer(); } ) - .then( function( bytes ) { return WebAssembly.compile( bytes ); } ) - .then( function( mod ) { return WebAssembly.instantiate( mod, instance.imports ) } ) ); - - return wasm_instance - .then( function( wasm_instance ) { - var exports = instance.initialize( wasm_instance ); - console.log( "Finished loading Rust wasm module 'helloworld'" ); - return exports; - }) - .catch( function( error ) { - console.log( "Error loading Rust wasm module 'helloworld':", error ); - throw error; - }); - } - }( function() { - var Module = {}; - - Module.STDWEB_PRIVATE = {}; - -// This is based on code from Emscripten's preamble.js. -Module.STDWEB_PRIVATE.to_utf8 = function to_utf8( str, addr ) { - var HEAPU8 = Module.HEAPU8; - for( var i = 0; i < str.length; ++i ) { - // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8. - // See http://unicode.org/faq/utf_bom.html#utf16-3 - // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description and https://www.ietf.org/rfc/rfc2279.txt and https://tools.ietf.org/html/rfc3629 - var u = str.charCodeAt( i ); // possibly a lead surrogate - if( u >= 0xD800 && u <= 0xDFFF ) { - u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt( ++i ) & 0x3FF); - } - - if( u <= 0x7F ) { - HEAPU8[ addr++ ] = u; - } else if( u <= 0x7FF ) { - HEAPU8[ addr++ ] = 0xC0 | (u >> 6); - HEAPU8[ addr++ ] = 0x80 | (u & 63); - } else if( u <= 0xFFFF ) { - HEAPU8[ addr++ ] = 0xE0 | (u >> 12); - HEAPU8[ addr++ ] = 0x80 | ((u >> 6) & 63); - HEAPU8[ addr++ ] = 0x80 | (u & 63); - } else if( u <= 0x1FFFFF ) { - HEAPU8[ addr++ ] = 0xF0 | (u >> 18); - HEAPU8[ addr++ ] = 0x80 | ((u >> 12) & 63); - HEAPU8[ addr++ ] = 0x80 | ((u >> 6) & 63); - HEAPU8[ addr++ ] = 0x80 | (u & 63); - } else if( u <= 0x3FFFFFF ) { - HEAPU8[ addr++ ] = 0xF8 | (u >> 24); - HEAPU8[ addr++ ] = 0x80 | ((u >> 18) & 63); - HEAPU8[ addr++ ] = 0x80 | ((u >> 12) & 63); - HEAPU8[ addr++ ] = 0x80 | ((u >> 6) & 63); - HEAPU8[ addr++ ] = 0x80 | (u & 63); - } else { - HEAPU8[ addr++ ] = 0xFC | (u >> 30); - HEAPU8[ addr++ ] = 0x80 | ((u >> 24) & 63); - HEAPU8[ addr++ ] = 0x80 | ((u >> 18) & 63); - HEAPU8[ addr++ ] = 0x80 | ((u >> 12) & 63); - HEAPU8[ addr++ ] = 0x80 | ((u >> 6) & 63); - HEAPU8[ addr++ ] = 0x80 | (u & 63); - } - } -}; - -Module.STDWEB_PRIVATE.noop = function() {}; -Module.STDWEB_PRIVATE.to_js = function to_js( address ) { - var kind = Module.HEAPU8[ address + 12 ]; - if( kind === 0 ) { - return undefined; - } else if( kind === 1 ) { - return null; - } else if( kind === 2 ) { - return Module.HEAP32[ address / 4 ]; - } else if( kind === 3 ) { - return Module.HEAPF64[ address / 8 ]; - } else if( kind === 4 ) { - var pointer = Module.HEAPU32[ address / 4 ]; - var length = Module.HEAPU32[ (address + 4) / 4 ]; - return Module.STDWEB_PRIVATE.to_js_string( pointer, length ); - } else if( kind === 5 ) { - return false; - } else if( kind === 6 ) { - return true; - } else if( kind === 7 ) { - var pointer = Module.STDWEB_PRIVATE.arena + Module.HEAPU32[ address / 4 ]; - var length = Module.HEAPU32[ (address + 4) / 4 ]; - var output = []; - for( var i = 0; i < length; ++i ) { - output.push( Module.STDWEB_PRIVATE.to_js( pointer + i * 16 ) ); - } - return output; - } else if( kind === 8 ) { - var arena = Module.STDWEB_PRIVATE.arena; - var value_array_pointer = arena + Module.HEAPU32[ address / 4 ]; - var length = Module.HEAPU32[ (address + 4) / 4 ]; - var key_array_pointer = arena + Module.HEAPU32[ (address + 8) / 4 ]; - var output = {}; - for( var i = 0; i < length; ++i ) { - var key_pointer = Module.HEAPU32[ (key_array_pointer + i * 8) / 4 ]; - var key_length = Module.HEAPU32[ (key_array_pointer + 4 + i * 8) / 4 ]; - var key = Module.STDWEB_PRIVATE.to_js_string( key_pointer, key_length ); - var value = Module.STDWEB_PRIVATE.to_js( value_array_pointer + i * 16 ); - output[ key ] = value; - } - return output; - } else if( kind === 9 ) { - return Module.STDWEB_PRIVATE.acquire_js_reference( Module.HEAP32[ address / 4 ] ); - } else if( kind === 10 || kind === 12 || kind === 13 ) { - var adapter_pointer = Module.HEAPU32[ address / 4 ]; - var pointer = Module.HEAPU32[ (address + 4) / 4 ]; - var deallocator_pointer = Module.HEAPU32[ (address + 8) / 4 ]; - var num_ongoing_calls = 0; - var drop_queued = false; - var output = function() { - if( pointer === 0 || drop_queued === true ) { - if (kind === 10) { - throw new ReferenceError( "Already dropped Rust function called!" ); - } else if (kind === 12) { - throw new ReferenceError( "Already dropped FnMut function called!" ); - } else { - throw new ReferenceError( "Already called or dropped FnOnce function called!" ); - } - } - - var function_pointer = pointer; - if (kind === 13) { - output.drop = Module.STDWEB_PRIVATE.noop; - pointer = 0; - } - - if (num_ongoing_calls !== 0) { - if (kind === 12 || kind === 13) { - throw new ReferenceError( "FnMut function called multiple times concurrently!" ); - } - } - - var args = Module.STDWEB_PRIVATE.alloc( 16 ); - Module.STDWEB_PRIVATE.serialize_array( args, arguments ); - - try { - num_ongoing_calls += 1; - Module.STDWEB_PRIVATE.dyncall( "vii", adapter_pointer, [function_pointer, args] ); - var result = Module.STDWEB_PRIVATE.tmp; - Module.STDWEB_PRIVATE.tmp = null; - } finally { - num_ongoing_calls -= 1; - } - - if( drop_queued === true && num_ongoing_calls === 0 ) { - output.drop(); - } - - return result; - }; - - output.drop = function() { - if (num_ongoing_calls !== 0) { - drop_queued = true; - return; - } - - output.drop = Module.STDWEB_PRIVATE.noop; - var function_pointer = pointer; - pointer = 0; - - if (function_pointer != 0) { - Module.STDWEB_PRIVATE.dyncall( "vi", deallocator_pointer, [function_pointer] ); - } - }; - - return output; - } else if( kind === 14 ) { - var pointer = Module.HEAPU32[ address / 4 ]; - var length = Module.HEAPU32[ (address + 4) / 4 ]; - var array_kind = Module.HEAPU32[ (address + 8) / 4 ]; - var pointer_end = pointer + length; - - switch( array_kind ) { - case 0: - return Module.HEAPU8.subarray( pointer, pointer_end ); - case 1: - return Module.HEAP8.subarray( pointer, pointer_end ); - case 2: - return Module.HEAPU16.subarray( pointer, pointer_end ); - case 3: - return Module.HEAP16.subarray( pointer, pointer_end ); - case 4: - return Module.HEAPU32.subarray( pointer, pointer_end ); - case 5: - return Module.HEAP32.subarray( pointer, pointer_end ); - case 6: - return Module.HEAPF32.subarray( pointer, pointer_end ); - case 7: - return Module.HEAPF64.subarray( pointer, pointer_end ); - } - } else if( kind === 15 ) { - return Module.STDWEB_PRIVATE.get_raw_value( Module.HEAPU32[ address / 4 ] ); - } -}; - -Module.STDWEB_PRIVATE.serialize_object = function serialize_object( address, value ) { - var keys = Object.keys( value ); - var length = keys.length; - var key_array_pointer = Module.STDWEB_PRIVATE.alloc( length * 8 ); - var value_array_pointer = Module.STDWEB_PRIVATE.alloc( length * 16 ); - Module.HEAPU8[ address + 12 ] = 8; - Module.HEAPU32[ address / 4 ] = value_array_pointer; - Module.HEAPU32[ (address + 4) / 4 ] = length; - Module.HEAPU32[ (address + 8) / 4 ] = key_array_pointer; - for( var i = 0; i < length; ++i ) { - var key = keys[ i ]; - var key_address = key_array_pointer + i * 8; - Module.STDWEB_PRIVATE.to_utf8_string( key_address, key ); - - Module.STDWEB_PRIVATE.from_js( value_array_pointer + i * 16, value[ key ] ); - } -}; - -Module.STDWEB_PRIVATE.serialize_array = function serialize_array( address, value ) { - var length = value.length; - var pointer = Module.STDWEB_PRIVATE.alloc( length * 16 ); - Module.HEAPU8[ address + 12 ] = 7; - Module.HEAPU32[ address / 4 ] = pointer; - Module.HEAPU32[ (address + 4) / 4 ] = length; - for( var i = 0; i < length; ++i ) { - Module.STDWEB_PRIVATE.from_js( pointer + i * 16, value[ i ] ); - } -}; - -// New browsers and recent Node -var cachedEncoder = ( typeof TextEncoder === "function" - ? new TextEncoder( "utf-8" ) - // Old Node (before v11) - : ( typeof util === "object" && util && typeof util.TextEncoder === "function" - ? new util.TextEncoder( "utf-8" ) - // Old browsers - : null ) ); - -if ( cachedEncoder != null ) { - Module.STDWEB_PRIVATE.to_utf8_string = function to_utf8_string( address, value ) { - var buffer = cachedEncoder.encode( value ); - var length = buffer.length; - var pointer = 0; - - if ( length > 0 ) { - pointer = Module.STDWEB_PRIVATE.alloc( length ); - Module.HEAPU8.set( buffer, pointer ); - } - - Module.HEAPU32[ address / 4 ] = pointer; - Module.HEAPU32[ (address + 4) / 4 ] = length; - }; - -} else { - Module.STDWEB_PRIVATE.to_utf8_string = function to_utf8_string( address, value ) { - var length = Module.STDWEB_PRIVATE.utf8_len( value ); - var pointer = 0; - - if ( length > 0 ) { - pointer = Module.STDWEB_PRIVATE.alloc( length ); - Module.STDWEB_PRIVATE.to_utf8( value, pointer ); - } - - Module.HEAPU32[ address / 4 ] = pointer; - Module.HEAPU32[ (address + 4) / 4 ] = length; - }; -} - -Module.STDWEB_PRIVATE.from_js = function from_js( address, value ) { - var kind = Object.prototype.toString.call( value ); - if( kind === "[object String]" ) { - Module.HEAPU8[ address + 12 ] = 4; - Module.STDWEB_PRIVATE.to_utf8_string( address, value ); - } else if( kind === "[object Number]" ) { - if( value === (value|0) ) { - Module.HEAPU8[ address + 12 ] = 2; - Module.HEAP32[ address / 4 ] = value; - } else { - Module.HEAPU8[ address + 12 ] = 3; - Module.HEAPF64[ address / 8 ] = value; - } - } else if( value === null ) { - Module.HEAPU8[ address + 12 ] = 1; - } else if( value === undefined ) { - Module.HEAPU8[ address + 12 ] = 0; - } else if( value === false ) { - Module.HEAPU8[ address + 12 ] = 5; - } else if( value === true ) { - Module.HEAPU8[ address + 12 ] = 6; - } else if( kind === "[object Symbol]" ) { - var id = Module.STDWEB_PRIVATE.register_raw_value( value ); - Module.HEAPU8[ address + 12 ] = 15; - Module.HEAP32[ address / 4 ] = id; - } else { - var refid = Module.STDWEB_PRIVATE.acquire_rust_reference( value ); - Module.HEAPU8[ address + 12 ] = 9; - Module.HEAP32[ address / 4 ] = refid; - } -}; - -// New browsers and recent Node -var cachedDecoder = ( typeof TextDecoder === "function" - ? new TextDecoder( "utf-8" ) - // Old Node (before v11) - : ( typeof util === "object" && util && typeof util.TextDecoder === "function" - ? new util.TextDecoder( "utf-8" ) - // Old browsers - : null ) ); - -if ( cachedDecoder != null ) { - Module.STDWEB_PRIVATE.to_js_string = function to_js_string( index, length ) { - return cachedDecoder.decode( Module.HEAPU8.subarray( index, index + length ) ); - }; - -} else { - // This is ported from Rust's stdlib; it's faster than - // the string conversion from Emscripten. - Module.STDWEB_PRIVATE.to_js_string = function to_js_string( index, length ) { - var HEAPU8 = Module.HEAPU8; - index = index|0; - length = length|0; - var end = (index|0) + (length|0); - var output = ""; - while( index < end ) { - var x = HEAPU8[ index++ ]; - if( x < 128 ) { - output += String.fromCharCode( x ); - continue; - } - var init = (x & (0x7F >> 2)); - var y = 0; - if( index < end ) { - y = HEAPU8[ index++ ]; - } - var ch = (init << 6) | (y & 63); - if( x >= 0xE0 ) { - var z = 0; - if( index < end ) { - z = HEAPU8[ index++ ]; - } - var y_z = ((y & 63) << 6) | (z & 63); - ch = init << 12 | y_z; - if( x >= 0xF0 ) { - var w = 0; - if( index < end ) { - w = HEAPU8[ index++ ]; - } - ch = (init & 7) << 18 | ((y_z << 6) | (w & 63)); - - output += String.fromCharCode( 0xD7C0 + (ch >> 10) ); - ch = 0xDC00 + (ch & 0x3FF); - } - } - output += String.fromCharCode( ch ); - continue; - } - return output; - }; -} - -Module.STDWEB_PRIVATE.id_to_ref_map = {}; -Module.STDWEB_PRIVATE.id_to_refcount_map = {}; -Module.STDWEB_PRIVATE.ref_to_id_map = new WeakMap(); -// Not all types can be stored in a WeakMap -Module.STDWEB_PRIVATE.ref_to_id_map_fallback = new Map(); -Module.STDWEB_PRIVATE.last_refid = 1; - -Module.STDWEB_PRIVATE.id_to_raw_value_map = {}; -Module.STDWEB_PRIVATE.last_raw_value_id = 1; - -Module.STDWEB_PRIVATE.acquire_rust_reference = function( reference ) { - if( reference === undefined || reference === null ) { - return 0; - } - - var id_to_refcount_map = Module.STDWEB_PRIVATE.id_to_refcount_map; - var id_to_ref_map = Module.STDWEB_PRIVATE.id_to_ref_map; - var ref_to_id_map = Module.STDWEB_PRIVATE.ref_to_id_map; - var ref_to_id_map_fallback = Module.STDWEB_PRIVATE.ref_to_id_map_fallback; - - var refid = ref_to_id_map.get( reference ); - if( refid === undefined ) { - refid = ref_to_id_map_fallback.get( reference ); - } - if( refid === undefined ) { - refid = Module.STDWEB_PRIVATE.last_refid++; - try { - ref_to_id_map.set( reference, refid ); - } catch (e) { - ref_to_id_map_fallback.set( reference, refid ); - } - } - - if( refid in id_to_ref_map ) { - id_to_refcount_map[ refid ]++; - } else { - id_to_ref_map[ refid ] = reference; - id_to_refcount_map[ refid ] = 1; - } - - return refid; -}; - -Module.STDWEB_PRIVATE.acquire_js_reference = function( refid ) { - return Module.STDWEB_PRIVATE.id_to_ref_map[ refid ]; -}; - -Module.STDWEB_PRIVATE.increment_refcount = function( refid ) { - Module.STDWEB_PRIVATE.id_to_refcount_map[ refid ]++; -}; - -Module.STDWEB_PRIVATE.decrement_refcount = function( refid ) { - var id_to_refcount_map = Module.STDWEB_PRIVATE.id_to_refcount_map; - if( 0 == --id_to_refcount_map[ refid ] ) { - var id_to_ref_map = Module.STDWEB_PRIVATE.id_to_ref_map; - var ref_to_id_map_fallback = Module.STDWEB_PRIVATE.ref_to_id_map_fallback; - var reference = id_to_ref_map[ refid ]; - delete id_to_ref_map[ refid ]; - delete id_to_refcount_map[ refid ]; - ref_to_id_map_fallback.delete(reference); - } -}; - -Module.STDWEB_PRIVATE.register_raw_value = function( value ) { - var id = Module.STDWEB_PRIVATE.last_raw_value_id++; - Module.STDWEB_PRIVATE.id_to_raw_value_map[ id ] = value; - return id; -}; - -Module.STDWEB_PRIVATE.unregister_raw_value = function( id ) { - delete Module.STDWEB_PRIVATE.id_to_raw_value_map[ id ]; -}; - -Module.STDWEB_PRIVATE.get_raw_value = function( id ) { - return Module.STDWEB_PRIVATE.id_to_raw_value_map[ id ]; -}; - -Module.STDWEB_PRIVATE.alloc = function alloc( size ) { - return Module.web_malloc( size ); -}; - -Module.STDWEB_PRIVATE.dyncall = function( signature, ptr, args ) { - return Module.web_table.get( ptr ).apply( null, args ); -}; - -// This is based on code from Emscripten's preamble.js. -Module.STDWEB_PRIVATE.utf8_len = function utf8_len( str ) { - var len = 0; - for( var i = 0; i < str.length; ++i ) { - // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8. - // See http://unicode.org/faq/utf_bom.html#utf16-3 - var u = str.charCodeAt( i ); // possibly a lead surrogate - if( u >= 0xD800 && u <= 0xDFFF ) { - u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt( ++i ) & 0x3FF); - } - - if( u <= 0x7F ) { - ++len; - } else if( u <= 0x7FF ) { - len += 2; - } else if( u <= 0xFFFF ) { - len += 3; - } else if( u <= 0x1FFFFF ) { - len += 4; - } else if( u <= 0x3FFFFFF ) { - len += 5; - } else { - len += 6; - } - } - return len; -}; - -Module.STDWEB_PRIVATE.prepare_any_arg = function( value ) { - var arg = Module.STDWEB_PRIVATE.alloc( 16 ); - Module.STDWEB_PRIVATE.from_js( arg, value ); - return arg; -}; - -Module.STDWEB_PRIVATE.acquire_tmp = function( dummy ) { - var value = Module.STDWEB_PRIVATE.tmp; - Module.STDWEB_PRIVATE.tmp = null; - return value; -}; - - - - var HEAP8 = null; - var HEAP16 = null; - var HEAP32 = null; - var HEAPU8 = null; - var HEAPU16 = null; - var HEAPU32 = null; - var HEAPF32 = null; - var HEAPF64 = null; - - Object.defineProperty( Module, 'exports', { value: {} } ); - - function __web_on_grow() { - var buffer = Module.instance.exports.memory.buffer; - HEAP8 = new Int8Array( buffer ); - HEAP16 = new Int16Array( buffer ); - HEAP32 = new Int32Array( buffer ); - HEAPU8 = new Uint8Array( buffer ); - HEAPU16 = new Uint16Array( buffer ); - HEAPU32 = new Uint32Array( buffer ); - HEAPF32 = new Float32Array( buffer ); - HEAPF64 = new Float64Array( buffer ); - Module.HEAP8 = HEAP8; - Module.HEAP16 = HEAP16; - Module.HEAP32 = HEAP32; - Module.HEAPU8 = HEAPU8; - Module.HEAPU16 = HEAPU16; - Module.HEAPU32 = HEAPU32; - Module.HEAPF32 = HEAPF32; - Module.HEAPF64 = HEAPF64; - } - - return { - imports: { - env: { - "__cargo_web_snippet_09675c7ed2827e045dc760aeac3d286437cfbe5e": function($0, $1, $2, $3) { - $1 = Module.STDWEB_PRIVATE.to_js($1);$2 = Module.STDWEB_PRIVATE.to_js($2);$3 = Module.STDWEB_PRIVATE.to_js($3);Module.STDWEB_PRIVATE.from_js($0, (function(){try{return{value:function(){return($1).setAttribute(($2),($3));}(),success:true};}catch(error){return{error:error,success:false};}})()); - }, - "__cargo_web_snippet_0e54fd9c163fcf648ce0a395fde4500fd167a40b": function($0) { - var r = Module.STDWEB_PRIVATE.acquire_js_reference( $0 );return (r instanceof DOMException) && (r.name === "InvalidCharacterError"); - }, - "__cargo_web_snippet_1edaec034bdcb0a749c6d5de76c29f6371afb5a0": function($0) { - var o = Module.STDWEB_PRIVATE.acquire_js_reference( $0 );return (o instanceof Event && o.type === "input"); - }, - "__cargo_web_snippet_2908dbb08792df5e699e324eec3e29fd6a57c2c9": function($0) { - var o = Module.STDWEB_PRIVATE.acquire_js_reference( $0 );return (o instanceof HTMLInputElement); - }, - "__cargo_web_snippet_3c5e83d16a83fc7147ec91e2506438012952f55a": function($0) { - var o = Module.STDWEB_PRIVATE.acquire_js_reference( $0 );return (o instanceof Element); - }, - "__cargo_web_snippet_614a3dd2adb7e9eac4a0ec6e59d37f87e0521c3b": function($0, $1) { - $1 = Module.STDWEB_PRIVATE.to_js($1);Module.STDWEB_PRIVATE.from_js($0, (function(){return($1).error;})()); - }, - "__cargo_web_snippet_6fcce0aae651e2d748e085ff1f800f87625ff8c8": function($0) { - Module.STDWEB_PRIVATE.from_js($0, (function(){return document;})()); - }, - "__cargo_web_snippet_72fc447820458c720c68d0d8e078ede631edd723": function($0, $1, $2) { - console.error( 'Panic location:', Module.STDWEB_PRIVATE.to_js_string( $0, $1 ) + ':' + $2 ); - }, - "__cargo_web_snippet_80d6d56760c65e49b7be8b6b01c1ea861b046bf0": function($0) { - Module.STDWEB_PRIVATE.decrement_refcount( $0 ); - }, - "__cargo_web_snippet_91749aeb589cd0f9b17cbc01b2872ba709817982": function($0, $1, $2) { - $1 = Module.STDWEB_PRIVATE.to_js($1);$2 = Module.STDWEB_PRIVATE.to_js($2);Module.STDWEB_PRIVATE.from_js($0, (function(){try{return{value:function(){return($1).createElement(($2));}(),success:true};}catch(error){return{error:error,success:false};}})()); - }, - "__cargo_web_snippet_97495987af1720d8a9a923fa4683a7b683e3acd6": function($0, $1) { - console.error( 'Panic error message:', Module.STDWEB_PRIVATE.to_js_string( $0, $1 ) ); - }, - "__cargo_web_snippet_99c4eefdc8d4cc724135163b8c8665a1f3de99e4": function($0, $1, $2, $3) { - $1 = Module.STDWEB_PRIVATE.to_js($1);$2 = Module.STDWEB_PRIVATE.to_js($2);$3 = Module.STDWEB_PRIVATE.to_js($3);Module.STDWEB_PRIVATE.from_js($0, (function(){var listener=($1);($2).addEventListener(($3),listener);return listener;})()); - }, - "__cargo_web_snippet_9f22d4ca7bc938409787341b7db181f8dd41e6df": function($0) { - Module.STDWEB_PRIVATE.increment_refcount( $0 ); - }, - "__cargo_web_snippet_ab05f53189dacccf2d365ad26daa407d4f7abea9": function($0, $1) { - $1 = Module.STDWEB_PRIVATE.to_js($1);Module.STDWEB_PRIVATE.from_js($0, (function(){return($1).value;})()); - }, - "__cargo_web_snippet_afafe9a462a05084fec65cacc7d6598e145ff3e3": function($0, $1, $2) { - $1 = Module.STDWEB_PRIVATE.to_js($1);$2 = Module.STDWEB_PRIVATE.to_js($2);Module.STDWEB_PRIVATE.from_js($0, (function(){return($1).createTextNode(($2));})()); - }, - "__cargo_web_snippet_b06dde4acf09433b5190a4b001259fe5d4abcbc2": function($0, $1) { - $1 = Module.STDWEB_PRIVATE.to_js($1);Module.STDWEB_PRIVATE.from_js($0, (function(){return($1).success;})()); - }, - "__cargo_web_snippet_d5e30f74cb752784e06bd97a37b1f89b6c3433a7": function($0, $1, $2) { - $1 = Module.STDWEB_PRIVATE.to_js($1);$2 = Module.STDWEB_PRIVATE.to_js($2);Module.STDWEB_PRIVATE.from_js($0, (function(){return($1).getElementById(($2));})()); - }, - "__cargo_web_snippet_dc2fd915bd92f9e9c6a3bd15174f1414eee3dbaf": function() { - console.error( 'Encountered a panic!' ); - }, - "__cargo_web_snippet_e741b9d9071097746386b2c2ec044a2bc73e688c": function($0, $1) { - $0 = Module.STDWEB_PRIVATE.to_js($0);$1 = Module.STDWEB_PRIVATE.to_js($1);($0).appendChild(($1)); - }, - "__cargo_web_snippet_e9638d6405ab65f78daf4a5af9c9de14ecf1e2ec": function($0) { - $0 = Module.STDWEB_PRIVATE.to_js($0);Module.STDWEB_PRIVATE.unregister_raw_value(($0)); - }, - "__cargo_web_snippet_f765b15a1a1b5cd266e922e6fca98dd570f17edc": function($0, $1) { - $0 = Module.STDWEB_PRIVATE.to_js($0);$1 = Module.STDWEB_PRIVATE.to_js($1);($0).textContent=($1); - }, - "__cargo_web_snippet_ff5103e6cc179d13b4c7a785bdce2708fd559fc0": function($0) { - Module.STDWEB_PRIVATE.tmp = Module.STDWEB_PRIVATE.to_js( $0 ); - }, - "__web_on_grow": __web_on_grow - } - }, - initialize: function( instance ) { - Object.defineProperty( Module, 'instance', { value: instance } ); - Object.defineProperty( Module, 'web_malloc', { value: Module.instance.exports.__web_malloc } ); - Object.defineProperty( Module, 'web_free', { value: Module.instance.exports.__web_free } ); - Object.defineProperty( Module, 'web_table', { value: Module.instance.exports.__indirect_function_table } ); - - - __web_on_grow(); - Module.instance.exports.main(); - - return Module.exports; - } - }; -} - )); -})); diff --git a/content/enterprise/2020-02-11-prototype/helloworld.wasm b/content/enterprise/2020-02-11-prototype/helloworld.wasm deleted file mode 100644 index 3d6ced2..0000000 Binary files a/content/enterprise/2020-02-11-prototype/helloworld.wasm and /dev/null differ diff --git a/content/enterprise/2020-02-11-prototype/index.md b/content/enterprise/2020-02-11-prototype/index.md deleted file mode 100644 index b7e9b5b..0000000 --- a/content/enterprise/2020-02-11-prototype/index.md +++ /dev/null @@ -1,101 +0,0 @@ -+++ -title = "enterprise: a new ui framework" -date = 2020-02-11 -template = "post.html" - -[taxonomies] -tags = ["computers", "web-dev"] -+++ - -This past weekend, while on my trip to Minneapolis, I completed a very early prototype of "enterprise", a new UI framework I've been kind of envisioning over the past couple of weeks. While the UI framework is mainly targeted at web apps, the hope is that with a bit more effort, native UIs can be produced with almost no changes to existing applications. Before I begin to describe how it works, I'd like to acknowledge [Nathan Ringo][1] for his massively helpful feedback in both the brainstorming and the implementation process. - - - -## Goals of the project - -This project was born out of many frustrations with existing web frameworks. This is kind of the combination of several projects I wanted to tackle; since it's such a long-term thing I'm going to document a bit of what I want to achieve so I can stay on track. The high-level goals of the project are: - -* **Complete separation of business logic from UI.** Theoretically, one could completely retarget the application to a completely different platform (mobile, web, native, something new that will pop up in 5 years), without changing any of the core logic. It does this by introducing [declarative][4]-style [DSL][2]s that are completely architecture-independent. -* **Maximally static component relationships.** Like [Svelte][3], I'm aiming to resolve as many relationships between elements as possible during compile-time, to avoid having to maintain a full virtual DOM at runtime. - -With that, let's dive into the code! - -## Demo: Initial Prototype - -The prototype for experimenting is a simple "Hello, world" application. If you've looked at any web framework before, this is probably one of the simplest examples of bindings: type something into a box and watch as the text magically populates with whatever you wrote in the box. If you're using a WASM-compatible browser with JavaScript enabled, you should be able to try out the demo right here: - -
- - -OK, you say, but I could implement this in 3 lines of JavaScript. - -```js -inputEl.addEventListener("change", () => { - spanEl.innerText = inputEl.value; -}); -``` - -Sure, this works, but it doesn't scale. If you try to write a page full of these kind of bindings directly using JavaScript, you're either going to start running into bugs or building up a pile of unmaintainable spaghetti code. How does enterprise represent this? Well, the enterprise DSL has no concrete syntax yet, but if it did, it would look something like this: - -``` -model { - name: String, -} - -view { - - Hello, {name}! -} -``` - -This looks a lot closer to {React, Vue, Svelte, component structure}-ish code. The idea now is that the "compiler", as I've come to call it, reads the entire specification of the code and creates a sort of dependency graph of actions. For clarity, let's assign some IDs first: - -* Let the `TextBox`'s value attribute be `view_value`. -* Let the `{name}` code segment in "Hello, name" be `view_name`. -* Let the model's name field be `model_name`. - -Now we can model this as: - -```dot -digraph "dependency graph" { - graph[bgcolor="transparent", class="default-coloring"]; - rankdir="LR"; - - "view_value" -> "model_name" - "model_name" -> "view_name" -} -``` - -The arrows in this graph indicate a dependency where changes to `view_value` propagates down the graph until everything else is changed. For the initial prototype, the data structure passed through this graph is simply a string, but with encoding magic and additional specifications, we can add rich text later. What this means the compiler then generates code that looks something like (but not exactly): - -```rs -fn create_view_value(model: &mut Model) -> INode { - let el = (...); - el.add_event_listener(|evt: InputListener| { - let new_value = el.get_attribute("value"); - model.name = new_value; - view_name.set_text(new_value); - }); - el -} -``` - -There's some complications involving the exact model representation in memory as well as how web attributes are accessed that makes the real code a bit different, but from this example you should be able to see that our "compiler" generated real code that matches our specification above. - -The full code for this can be found [here][5]. - -## Future - -Obviously not everyone's application is as simple as a linear dependency graph of simple string values. In fact, I even cheated a bit to get this prototype to function; here's some of the shortcuts I took: - -* I mostly hardcoded web elements in instead of making platform-independent abstractions. -* I hardcoded the actual specification for the app myself since the DSL doesn't have a real syntax yet. -* All data are string types. - -I'll be working on this some more in the coming weeks, so I'll try to keep updates posted here a bit more frequently. Next time, I'll be looking into implementing the TodoMVC example. Until then, thanks for reading! - -[1]: https://remexre.xyz -[2]: https://en.wikipedia.org/wiki/Domain-specific_language -[3]: https://svelte.dev -[4]: https://en.wikipedia.org/wiki/Declarative_programming -[5]: https://git.iptq.io/michael/enterprise diff --git a/content/enterprise/2020-02-17-syntax-update.md b/content/enterprise/2020-02-17-syntax-update.md deleted file mode 100644 index d8863f6..0000000 --- a/content/enterprise/2020-02-17-syntax-update.md +++ /dev/null @@ -1,100 +0,0 @@ -+++ -title = "enterprise: syntax update" -date = 2020-02-17 -template = "post.html" - -[taxonomies] -tags = ["computers", "web-dev"] -+++ - -[Enterprise][1]'s frontend DSL just got a syntax! Although the major functionality hasn't really changed, I threw out the ugly verbose AST-construction syntax for a hand-rolled recursive-descent-ish parser. - - - -The rehashed "Hello, world" example looks a bit like this: - -``` -component HelloWorld { - model { - name: String = "hello", - } - - view { - - "Hello, " {name} "!" - } -} -``` - -This compiles using `cargo-web` into a working version of the last post's prototype. You'll notice that quoted literals are used to represent text rather than just typing it out directly like in XML. This is because I'm actually borrowing Rust syntax and parsing it a bit differently. If I had bare text, then everything you put would have to follow Rust's lexical rules; additionally, data about spacing would be a lot more complicated (and unstable!) to retrieve. - -I could possibly have thrown the whole thing into a parser-generator, using Rust's `proc-macro::TokenTree` as tokens, but TokenTree actually gives you blocks (eg. `()` `{}` `[]`) for free, so I can parse expressions like `{name}` incredibly easily. - -Syntax isn't the only thing that's changed since the last update: I've also revamped how builds work. - -New Build Method ----------------- - -I'm switching to a build method that's rather unconventional. The original approach looked something like this. - -```dot -digraph "dependency graph" { - graph[bgcolor="transparent", class="default-coloring"]; - rankdir="LR"; - - "Component DSL" -> "AST" [label = "Parsing"]; - "AST" -> "Dependency Graph" [label = "Graph traversal"]; -} -``` - -Problem here is, when we want code to be modular, the graph traversal approach is going to need information about _all_ modules that are imported in order to -be able to produce a flat set of instructions in the final result. If I make a library for a component (say, `enterprise-router`), what should its crate's contents be? - -> **Tangent**: Here's where I'm going to distract myself a little and put this into a more big-picture perspective. Ultimately, the ideal manifestation of an architecture/business-logic separation would be a DSL that completely hides all implementation of its internals. -> -> That's a pretty far-out goal, so I'm building enterprise incrementally. Sadly, large parts of the language will still rely on the language in which this framework is implemented, Rust. This means that the underlying implementation of features such as modules and async will be relying on the Rust language having these features. However, note that in the long term, a separate DSL for business logic will be planned. - -So what's the solution here? Instead of visiting your component node by node when your component is defined, all the framework is going to do is parse your definition and store the AST of your component as-is. I chose here to serialize ASTs as JSON data and dump it into a static string that will be bundled into your crate. - -Then, in your `build.rs` file, you'll call something like `enterprise_compiler::build(App)`, where `App` is the name of the static string containing the JSON data of the description of your app. This will actually perform the analysis process, calculating the graph of update dependencies, as well as generating the code that will go into a Rust module that you can include into your code. - -Your `build.rs` file might look something like this: - -```rs -#[macro_use] -extern crate enterprise_macros; - -component! { - component HelloWorld { - model { - name: String = "hello", - } - - view { - - "Hello, " {name} "!" - } - } -} - -fn main() { - enterprise_compiler::process("helloworld", HelloWorld); -} -``` - -This will create a string called `HelloWorld` for the HelloWorld component, and then analyze and generate the final application code for it into a file called `helloworld.rs` that you can `mod` into your application. The advantage to this approach is that external modules can just rely on Rust's crate system, since we're just fetching strings out of other crates. - -Source code: [here][3]. - -Next Steps ----------- - -As mentioned in my previous post, I'm still working on implementing [TodoMVC][2], a simple Todo application that should flesh out some more of the reactive functionalities of the framework. This should solidify some more of the questions regarding interactions between data model and DOM. - -I'll also try to abstract more of the system away so it's less dependent on stdweb's implementation. This means adding a notion of "backend", where different backends may have different implementations of a particular component. - - - -[1]: @/enterprise/2020-02-11-prototype/index.md -[2]: http://todomvc.com/ -[3]: https://git.iptq.io/michael/enterprise/src/commit/1453885ed2c3a5159431bb41398b9b8bea4d49f5 diff --git a/content/enterprise/_index.md b/content/enterprise/_index.md deleted file mode 100644 index 7085772..0000000 --- a/content/enterprise/_index.md +++ /dev/null @@ -1,7 +0,0 @@ -+++ -template = "blog.html" -insert_anchor_links = "left" - -[extra] -include_posts = true -+++ diff --git a/content/pages/_index.md b/content/pages/_index.md deleted file mode 100644 index b31ce26..0000000 --- a/content/pages/_index.md +++ /dev/null @@ -1,9 +0,0 @@ -+++ -title = "all pages" -template = "listing.html" -page_template = "post.html" -insert_anchor_links = "left" - -[extra] -include_posts = false -+++ diff --git a/content/pages/about.md b/content/pages/about.md deleted file mode 100644 index 5b06847..0000000 --- a/content/pages/about.md +++ /dev/null @@ -1,16 +0,0 @@ -+++ -title = "about me" -+++ - -Hi there! I'm a software developer at Epic Systems in Verona, Wisconsin, and I recently graduated with a Computer Science degree from the University of Minnesota. I've got a wide variety of interests under this field. I've been doing web development for a long time and now I'm looking into security, programming language development, and software development! - -In an effort to rely on less services, I started doing a lot of self-hosting and rewriting of software. Check out some of the projects I'm doing over on my public [Gitea](https://git.iptq.io)! - -If you want my resume, contact me through one of these means: - -## contact -- Discord: **iptq#8440** -- Email: (I sign all my Git commits with this email) -- PGP Key: [hosted on Keybase][1] - -[1]: https://keybase.io/michaelz/pgp_keys.asc?fingerprint=925ecc02890d5cdae26180d4bda47a31a3c8ee6b diff --git a/content/pages/projects.md b/content/pages/projects.md deleted file mode 100644 index afb7a2a..0000000 --- a/content/pages/projects.md +++ /dev/null @@ -1,11 +0,0 @@ -+++ -title = "projects" -+++ - -- **[garbage](https://github.com/iptq/garbage)**: A command-line tool for interfacing with the FreeDesktop trashcan spec. -- **[leanshot](https://github.com/iptq/leanshot)**: Linux screen capturing tool that freezes the screen before selecting. - -Other projects can be found: - -- [Github](https://github.com/iptq) -- [Gitea](https://git.iptq.io/explore) diff --git a/content/2018-02-01-my-new-life-stack.md b/content/posts/2018-02-01-my-new-life-stack.md similarity index 100% rename from content/2018-02-01-my-new-life-stack.md rename to content/posts/2018-02-01-my-new-life-stack.md diff --git a/content/2018-02-25-cleaning-up-your-shell.md b/content/posts/2018-02-25-cleaning-up-your-shell.md similarity index 100% rename from content/2018-02-25-cleaning-up-your-shell.md rename to content/posts/2018-02-25-cleaning-up-your-shell.md diff --git a/content/2018-04-23-fixing-tmux-colors.md b/content/posts/2018-04-23-fixing-tmux-colors.md similarity index 100% rename from content/2018-04-23-fixing-tmux-colors.md rename to content/posts/2018-04-23-fixing-tmux-colors.md diff --git a/content/2018-05-28-web-apps.md b/content/posts/2018-05-28-web-apps.md similarity index 100% rename from content/2018-05-28-web-apps.md rename to content/posts/2018-05-28-web-apps.md diff --git a/content/2018-10-26-twenty-years-of-rsa-attacks.md b/content/posts/2018-10-26-twenty-years-of-rsa-attacks.md similarity index 100% rename from content/2018-10-26-twenty-years-of-rsa-attacks.md rename to content/posts/2018-10-26-twenty-years-of-rsa-attacks.md diff --git a/content/2019-02-01-magic-forms-with-proc-macros.md b/content/posts/2019-02-01-magic-forms-with-proc-macros.md similarity index 100% rename from content/2019-02-01-magic-forms-with-proc-macros.md rename to content/posts/2019-02-01-magic-forms-with-proc-macros.md diff --git a/content/2019-03-04-server-analogy.md b/content/posts/2019-03-04-server-analogy.md similarity index 100% rename from content/2019-03-04-server-analogy.md rename to content/posts/2019-03-04-server-analogy.md diff --git a/content/2020-04-01-password-managers.md b/content/posts/2020-04-01-password-managers.md similarity index 100% rename from content/2020-04-01-password-managers.md rename to content/posts/2020-04-01-password-managers.md diff --git a/content/2020-04-12-drawing-bezier-curves.md b/content/posts/2020-04-12-drawing-bezier-curves.md similarity index 100% rename from content/2020-04-12-drawing-bezier-curves.md rename to content/posts/2020-04-12-drawing-bezier-curves.md diff --git a/content/posts/_index.md b/content/posts/_index.md new file mode 100644 index 0000000..b6e7465 --- /dev/null +++ b/content/posts/_index.md @@ -0,0 +1,6 @@ ++++ +title = "home" + +[cascade] +type = "posts" ++++ diff --git a/content/setup/2018-10-18-weechat-relay.md b/content/setup/2018-10-18-weechat-relay.md deleted file mode 100644 index 6810e99..0000000 --- a/content/setup/2018-10-18-weechat-relay.md +++ /dev/null @@ -1,87 +0,0 @@ -+++ -title = "setting up irc with weechat" -date = 2018-10-18 - -[taxonomies] -tags = ["computers", "irc", "setup", "things-that-are-good"] -+++ - -I've just recently discovered that weechat has a "relay" mode, which means it can act as a relay server to other clients (for example, my phone). If I leave an instance of weechat running on, say, my server that's always running, it can act as a bouncer and my phone can receive notifications for highlights as well. - -The android app I'm using is called [Weechat-Android][2]. On my laptop I'm using [Glowing Bear][5]. - -## step 1: tmux - -To achieve this setup, first I install [tmux][1], which separates the terminal from the session. This means I can leave the weechat instance running in the background and detach my current session from it. The command for this is: - -```bash -$ tmux new-session -s weechat -``` - -where the `-s` option just names the tmux session so it's not assigned some number. - -## step 2: add relay - -Now add a relay through weechat: - -``` -/relay add -``` - -where name is - -``` -[ipv4.][ipv6.][ssl.]name - ipv4: force use of IPv4 - ipv6: force use of IPv6 - ssl: enable SSL -``` - -according to the [documentation][3]. - -## step 2.5: ssl - -I'm using SSL on my relay endpoint, and I'd recommend anyone else to use it to. You could follow what the documentation says and generate a self-signed certificate, but getting a trusted certificate with [LetsEncrypt][4] is so easy there's almost no excuse not to do it. - -To start, install certbot, which is LetsEncrypt's handy bot that does everything for you. Once you're ready, run: - -```bash -$ sudo certbot certonly -``` - -We want the `certonly` option because by default, certbot will try to install it into an existing HTTP server, but we're not using it for HTTP. This command should dump some files into `/etc/letsencrypt/live/`. - -Finally, just concatenate the important files, `privkey.pem` and `fullchain.pem` in that order, into `~/.weechat/ssl/relay.pem` (you can change that path with `/set relay.network.ssl_cert_key`). The file should look like: - -``` ------BEGIN PRIVATE KEY----- -...data... ------END PRIVATE KEY----- ------BEGIN CERTIFICATE----- -...data... ------END CERTIFICATE----- -``` - -If your private key file starts with `BEGIN CERTIFICATE`, just change that to `BEGIN PRIVATE KEY` (change the END one too) and it should be fine. - -## step 3: set password - -Since weechat 1.6, the option to not use a password has been removed. So in order for clients to be able to connect to the server, you must set one using: - -``` -/set relay.network.password -``` - -The password should appear in asterisks in the weechat prompt box. - -## step 4: connect - -This depends on your setup, but you must make sure that your setup is reachable from the outside. Make sure the port that you chose for the relay is accessible through firewalls. - -That's it! If you're also using the android app to connect, just type in your host's address and password and you should be all good to go. - -[1]: https://wiki.archlinux.org/index.php/Tmux -[2]: https://github.com/ubergeek42/weechat-android -[3]: https://www.weechat.org/files/doc/stable/weechat_user.en.html#relay_commands -[4]: https://letsencrypt.org/ -[5]: https://www.glowing-bear.org/ diff --git a/content/setup/2020-05-04-command-line-email-with-aerc/aerc-mail.jpg b/content/setup/2020-05-04-command-line-email-with-aerc/aerc-mail.jpg deleted file mode 100644 index aa5be0f..0000000 Binary files a/content/setup/2020-05-04-command-line-email-with-aerc/aerc-mail.jpg and /dev/null differ diff --git a/content/setup/2020-05-04-command-line-email-with-aerc/index.md b/content/setup/2020-05-04-command-line-email-with-aerc/index.md deleted file mode 100644 index 57951fd..0000000 --- a/content/setup/2020-05-04-command-line-email-with-aerc/index.md +++ /dev/null @@ -1,195 +0,0 @@ -+++ -title = "command line email with aerc" -date = 2020-05-04 -insert_anchor_links = "left" - -[taxonomies] -tags = ["setup", "email", "protonmail"] - -[extra] -include_posts = true -toc = true -+++ - -I just set up command line email with my new work account and my [ProtonMail][1] account today! This article will be covering the full setup. - -![aerc screenshot](aerc-mail.jpg) - -## setting up proton-bridge - -ProtonMail is an email service that end-to-end encrypts its users' emails with PGP. As a result, it doesn't speak SMTP or IMAP directly, since email clients wouldn't know how to undo the encryption anyway. That's why they've provided [proton-bridge][2], a ([now][3]) open-source SMTP/IMAP server that translates their own API calls into SMTP/IMAP for your email clients. For security, it's best to run this locally, so that emails aren't exposed over the network after they're decrypted. - -For my setup, I have proton-bridge running as a systemd service. That means we have to deal with any interactive parts of the service so they're not popping up anymore. - -Firstly, we want to build the bridge without support for the GUI. We won't be using it anyway, so this eliminates the Qt dependency. - -Secondly, proton-bridge stores keys in an encrypted keyring, like [password-store][5]. My regular password-store is encrypted with my passphrase-protected GPG key, so I didn't want to use it since it'll be asking me for the passphrase again every time the timeout expires. We're going to make a separate GPG and password-store setup that will only be used for proton-bridge. Since it's all running locally anyway, we're _not_ to use a passphrase on this GPG key. - -Authenticating only happens once, and the local SMTP/IMAP password doesn't change very often, so we won't really care about that. We'll bundle this up into a couple of nice scripts and then have it configured to start on startup! - -### building proton-bridge - -To build proton-bridge without the GUI, we'll need to grab a copy of the [source][2]. Clone the repo and then change directory to it: - -```bash -git clone https://github.com/protonmail/proton-bridge -cd proton-bridge -``` - -As of now, there's no tagged releases, so let's just build straight from master. Peeking into the Makefile, there isn't a release build for the nogui option, so let's add it ourselves. Put this somewhere in the Makefile: - -```make -build-nogui: - PROTONMAIL_ENV= go build ${BUILD_FLAGS_NOGUI} ./cmd/Desktop-Bridge -``` - -Then run `make build-nogui` and you should get a binary called `Desktop-Bridge`. Don't authenticate just quite yet; we want to set up the keychain first so it stores it in the right place. - -### isolating the keychain - -proton-bridge needs a keychain to store the keys that it gets from authenticating. The bridge supports [password-store][5] and GNOME keyring, but I'll be setting up password-store here. The goal now is to create a password-store instance that's isolated from the default installation so it doesn't require any interactive prompts. - -For this part, I created two directories: the directory for the new GPG homedir, and the directory for the new password-store. If you're copy-pasting commands out of this post, I'd recommend you add these variables right now: - -```bash -export PASSWORD_STORE_DIR=/path/to/password/store -export GNUPGHOME=/path/to/gpg/home -``` - -...obviously replacing the paths with paths that you choose. These variables are used by `pass` and `gpg` to overwrite the default directories they use, so it's important to set them up. The next step is to make sure they both exist: - -```bash -mkdir -p $PASSWORD_STORE_DIR $GNUPGHOME -``` - -Now initialize the GPG key first. Run: - -```bash -gpg --full-generate-key -``` - -There should be an interactive prompt. Go through and answer the questions however you see fit. I'd recommend you make the key 4096 bits, never expire, and have no passphrase. This key should never leave your local machine, and you will almost never use it directly, so there should be no problem. - -Then, set up password-store. Run: - -```bash -pass init [gpg-id] -``` - -where `[gpg-id]` is some identifier for the key you just created (name or email works). - -At this point, you should test your configuration by running the `Desktop-Bridge` program with the `-c` option to open the prompt. Make sure you are able to log in and that rerunning the program should automatically run the bridge using the authenticated user without any interactive prompts. - -``` - Welcome to ProtonMail Bridge interactive shell - ___....___ - ^^ __..-:'':__:..:__:'':-..__ - _.-:__:.-:'': : : :'':-.:__:-._ - .':.-: : : : : : : : : :._:'. - _ :.': : : : : : : : : : : :'.: _ - [ ]: : : : : : : : : : : : : :[ ] - [ ]: : : : : : : : : : : : : :[ ] - :::::::::[ ]:__:__:__:__:__:__:__:__:__:__:__:__:__:[ ]::::::::::: - !!!!!!!!![ ]!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!![ ]!!!!!!!!!!! - ^^^^^^^^^[ ]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^[ ]^^^^^^^^^^^ - [ ] [ ] - [ ] [ ] - jgs [ ] [ ] - ~~^_~^~/ \~^-~^~ _~^-~_^~-^~_^~~-^~_~^~-~_~-^~_^/ \~^ ~~_ ^ ->>> login -Username: iptq -Password: -Authenticating ... -Adding account ... -``` - -### automating the whole process - -Now that the bridge is able to run independently, let's make a tiny wrapper script called `run-proton-bridge.sh` that calls it using the appropriate environment variables: - -```bash -#!/bin/bash - -# same as before -export PASSWORD_STORE_DIR=/path/to/password/store -export GNUPGHOME=/path/to/gpg/home - -exec /path/to/Desktop-Bridge $@ -``` - -Save this somewhere, give it executable permissions. - -Finally, we can add a systemd service that runs this whole business whenever the network is available. I'd recommend adding this as a user service rather than a system service. You can put this somewhere like `$HOME/.config/systemd/user/proton-bridge.service`: - -```systemd -[Unit] -After=network.target - -[Service] -Restart=always -ExecStart=/path/to/run-proton-bridge.sh - -[Install] -WantedBy=default.target -``` - -Run this service: - -``` -systemctl --user start proton-bridge -``` - -Enable it to have it auto-start: - -``` -systemctl --user enable proton-bridge -``` - -Bridge configuration should be complete at this point, so let's move on to configuring our mail client to work with it. - -## setting up aerc - -[aerc][4] is a new (**work-in-progress**) command-line mail client by Drew Devault. It features a familiar set of default keybinds, calls out to your favorite editor for composition, and DWIM for many other things. I just started using it today and had no problem getting used to the interface. - -The setup for basic SMTP/IMAP email accounts is actually pretty trivial. When you run aerc for the first time, or whenever you run the command `:new-account`, an interactive screen is brought up prompting you for the details about your mailbox. If your mail provider doesn't work immediately, jump into `#aerc` on freenode; the folks there are super helpful with different mail providers. - -### setting up aerc.. _with_ protonmail - -If you've been keeping up, then all the pieces should be in place for aerc to work with ProtonMail. There's just a tiny bit of glue we have to add to put it all together. - -**aerc does not allow untrusted certificates**. Since proton-bridge generates a self-signed cert, we'll need to trust this cert before we can do anything. There's not really an easy way to pull the certificate out, so I'd recommend just firing up the bridge and then connecting to it using the openssl client and then copy-pasting the certificate part: - -``` -$ openssl s_client -starttls imap -connect 127.0.0.1:1143 -showcerts -CONNECTED(00000003) -Can't use SSL_get_servername -depth=0 C = CH, O = Proton Technologies AG, OU = ProtonMail, CN = 127.0.0.1 -verify return:1 ---- -Certificate chain - 0 s:C = CH, O = Proton Technologies AG, OU = ProtonMail, CN = 127.0.0.1 - i:C = CH, O = Proton Technologies AG, OU = ProtonMail, CN = 127.0.0.1 ------BEGIN CERTIFICATE----- -... ------END CERTIFICATE----- ---- -Server certificate -subject=C = CH, O = Proton Technologies AG, OU = ProtonMail, CN = 127.0.0.1 -issuer=C = CH, O = Proton Technologies AG, OU = ProtonMail, CN = 127.0.0.1 -... -``` - -Take that huge chunk starting with the line `BEGIN CERTIFICATE` and ending with the line `END CERTIFICATE` and stick it into some file (ex. `protonmail.crt`). This is the self-signed cert we need to trust. - -Now we'll need to tell our system to allow this cert. This varies from system to system; I'm on an Arch machine, so I ran: - -``` -sudo trust anchor --store protonmail.crt -``` - -After this, fire up `aerc` again, and your emails should start showing up. - -[1]: https://protonmail.com/ -[2]: https://github.com/ProtonMail/proton-bridge -[3]: https://protonmail.com/blog/bridge-open-source/ -[4]: https://aerc-mail.org/ diff --git a/content/setup/_index.md b/content/setup/_index.md deleted file mode 100644 index 8f199a2..0000000 --- a/content/setup/_index.md +++ /dev/null @@ -1,11 +0,0 @@ -+++ -template = "blog.html" -insert_anchor_links = "left" - -[extra] -include_posts = true -+++ - -# setup - -These posts are tutorial-style articles for setting things up. diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html new file mode 100644 index 0000000..91a4fe0 --- /dev/null +++ b/layouts/_default/baseof.html @@ -0,0 +1,43 @@ + + + + + + + {{ $style := resources.Get "sass/main.scss" | resources.ToCSS }} + + + + +
+ +
+ +
+ {{ block "content" . }}{{ end }} +
+ +
+

+ tags · + all pages +

+

+ written by michael zhang. + source +

+
+ + diff --git a/layouts/generic/list.html b/layouts/generic/list.html new file mode 100644 index 0000000..518d438 --- /dev/null +++ b/layouts/generic/list.html @@ -0,0 +1,5 @@ +{{- define "content" -}} + +{{ .Content }} + +{{- end -}} diff --git a/layouts/home.html b/layouts/home.html new file mode 100644 index 0000000..6180200 --- /dev/null +++ b/layouts/home.html @@ -0,0 +1,7 @@ +{{- define "content" -}} + +{{ $posts := .GetPage "/posts" }} + +{{ partial "post-list" $posts }} + +{{- end -}} diff --git a/layouts/partials/post-list.html b/layouts/partials/post-list.html new file mode 100644 index 0000000..5497d94 --- /dev/null +++ b/layouts/partials/post-list.html @@ -0,0 +1,19 @@ + + {{- range .Pages -}} + + + + {{- end -}} +
+ + {{ .Title }} + +
+ + {{ .ReadingTime }} min read - + + Posted + + on {{ .Date.Format "Mon Jan 2 2006" }} + +
diff --git a/layouts/posts/list.html b/layouts/posts/list.html new file mode 100644 index 0000000..b16f68f --- /dev/null +++ b/layouts/posts/list.html @@ -0,0 +1,7 @@ +{{- define "content" -}} + +{{ .Content }} + +{{ partial "post-list" . }} + +{{- end -}} diff --git a/layouts/posts/single.html b/layouts/posts/single.html new file mode 100644 index 0000000..e783d6b --- /dev/null +++ b/layouts/posts/single.html @@ -0,0 +1,20 @@ +{{- define "content" -}} + +« back +

{{ .Title }}

+ + + Posted + on {{ .Date }} + - {{ .ReadingTime }} min read + + +
{{ .Content }}
+ +
+ + + End. + + +{{- end -}} diff --git a/sass/_graph.scss b/sass/_graph.scss deleted file mode 100644 index 0b8b8cc..0000000 --- a/sass/_graph.scss +++ /dev/null @@ -1,22 +0,0 @@ -.graphviz { - margin: 24px auto; - - svg { - max-width: 100%; - width: 100%; - - .graph.default-coloring { - ellipse, path, polygon { - stroke: $text-color; - } - - text { - fill: $text-color; - } - - * { - font-family: $sansfont; - } - } - } -} diff --git a/static/.well-known/keybase.txt b/static/.well-known/keybase.txt deleted file mode 100644 index 2d143fb..0000000 --- a/static/.well-known/keybase.txt +++ /dev/null @@ -1,56 +0,0 @@ -================================================================== -https://keybase.io/michaelz --------------------------------------------------------------------- - -I hereby claim: - - * I am an admin of https://mzhang.me - * I am michaelz (https://keybase.io/michaelz) on keybase. - * I have a public key ASCEhMaJMl3DkJKGSXc8q1Nr5FIMVapUMwtEbQkCH7vIQAo - -To do so, I am signing this object: - -{ - "body": { - "key": { - "eldest_kid": "01208484c689325dc390928649773cab536be4520c55aa54330b446d09021fbbc8400a", - "host": "keybase.io", - "kid": "01208484c689325dc390928649773cab536be4520c55aa54330b446d09021fbbc8400a", - "uid": "601f28af1374f456f494088799b48f19", - "username": "michaelz" - }, - "merkle_root": { - "ctime": 1534063641, - "hash": "3d90ca7aa9d1224c4001d3d74c6eece550b1d573997ad1195747524aed8ca8c78e906659279835411ff6318f32e5cc3473bcb17d59e805bc4c09c894a85b2133", - "hash_meta": "4b048995ed39d76081818e6a3e1e5ecbf2a0f162dd919ce85c9fbbd8950f623c", - "seqno": 3444517 - }, - "service": { - "entropy": "BOxM8Iu2jNXojZrry8ZRRLQD", - "hostname": "mzhang.me", - "protocol": "https:" - }, - "type": "web_service_binding", - "version": 2 - }, - "client": { - "name": "keybase.io go client", - "version": "2.6.0" - }, - "ctime": 1534063667, - "expire_in": 504576000, - "prev": "df6a6156d48e0f9046ef4affcc78b05f4c82da914d659e02341b8e8d3c217989", - "seqno": 7, - "tag": "signature" -} - -which yields the signature: - -hKRib2R5hqhkZXRhY2hlZMOpaGFzaF90eXBlCqNrZXnEIwEghITGiTJdw5CShkl3PKtTa+RSDFWqVDMLRG0JAh+7yEAKp3BheWxvYWTESpcCB8Qg32phVtSOD5BG70r/zHiwX0yC2pFNZZ4CNBuOjTwheYnEIAOx/LG+C3XhAyJjoChBG6x3Az4Vvzi1M7EpYutmnJGRAgHCo3NpZ8RAKgWmEL7VKAfgctrw08z1aKv5GSK8mLetN4P5QOiLwcWPE0NE1Hos/pWu+xwNVwIKl2s/KRnh+juroUz0cMsEBKhzaWdfdHlwZSCkaGFzaIKkdHlwZQildmFsdWXEIJ/cZqfnA/IYJK7f2DgwLiQwXt88D1c/bhjdD5Lzt9HHo3RhZ80CAqd2ZXJzaW9uAQ== - -And finally, I am proving ownership of this host by posting or -appending to this document. - -View my publicly-auditable identity here: https://keybase.io/michaelz - -================================================================== diff --git a/static/.well-known/matrix/server b/static/.well-known/matrix/server deleted file mode 100644 index 7981261..0000000 --- a/static/.well-known/matrix/server +++ /dev/null @@ -1 +0,0 @@ -{ "m.server": "matrix.iptq.io:443" } diff --git a/static/pub.key b/static/pub.key deleted file mode 100644 index 04476bd..0000000 --- a/static/pub.key +++ /dev/null @@ -1,2 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC5XlB/S3z+WErLjskIkEU4+WmuRZh3eHQCgN//fxondOjODHNUIBydAY+7A4PTfvPwvhRKMIATkVCcRtaT3biqL8PZA7ov2Ul3naGsi42nNc4MHi76mZ82LUtuhdRIKIBMsJrR22pW/LLgD4tLqfiaKwzijULFkdaPBdElP4S+dbLb7m3CaugwXcJqHzHTS/iGZyC4uD296NlnammB/vANLhWtGGWobnaieFfFaUNoNrT0T6z1zY4TFIRKshT5HixIhn8qFJuMcyyjVeimNWekSLyo1UKwxLVkAhu1jAnd8C6g0X3vFbhthCLQqBSlxGtLjJRVRAU2WjiXZsleJXsOBuhDj8GnanPZwVNBgjwNPIKY5X17WAFm324SQD6Hyc1qUMvGoKo5OmLulBBX6Z9uwSLCe5q9clEwcqqf0KCOQasNkDlUTw34T2Xc47yycc/2UgVnfrXFAteFdjmnuvQRRc8J5Gk/R+sclmQNE9v4TPr4gdwiaz2xpclYyy5NhP+4u1G6ovzH/jePm2a3ZyejPEzy1JXZp5HwzgTL7WcPq+NHAgNOJ3wn7dxI8MZogzjEdGdQDfe1ckh4BKl9PlZ+q9IZvECAm3HVJ5u4N8sF3KmmCQwCPPhoueZF6GzoMnG4fbs1N1jyO0K1nfwnFjwz8E9hiWAyEpEZPjndJzs37Q== (none) - diff --git a/templates/404.html b/templates/404.html deleted file mode 100644 index f19c0c3..0000000 --- a/templates/404.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "layout.html" %} - -{% block title %} - 404 - {{ config.title }} -{% endblock %} - -{% block content %} -

nothing here

-

top

-{% endblock %} diff --git a/templates/anchor-link.html b/templates/anchor-link.html deleted file mode 100644 index d9172b4..0000000 --- a/templates/anchor-link.html +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/templates/blog.html b/templates/blog.html deleted file mode 100644 index 8afb061..0000000 --- a/templates/blog.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "layout.html" %} -{% import "macros/blog.html" as blog %} -{% import "macros/layout.html" as layout %} - -{% block title %} - {% if section.title %}{{ section.title }} - {% endif %} - {{ config.title }} -{% endblock %} - -{% block content %} - {{ section.content | safe }} - - {{ blog::sectionlisting(section=section) }} - -

- click here for RSS feed -

-{% endblock %} diff --git a/templates/layout.html b/templates/layout.html deleted file mode 100644 index fefab7a..0000000 --- a/templates/layout.html +++ /dev/null @@ -1,36 +0,0 @@ -{% import "macros/layout.html" as layout %} - - - - - - - - {% block title %}{% endblock %} - - - {% block headext %}{% endblock %} - - - -
- {{ layout::navbar(config=config) }} -
- -
- {% block content %}{% endblock %} -
- -
-

- tags · - all pages -

-

- written by michael zhang. - source -

-
- - - diff --git a/templates/listing.html b/templates/listing.html deleted file mode 100644 index db2daa7..0000000 --- a/templates/listing.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "layout.html" %} - -{% block title %} - {% if section.title %}{{ section.title }} - {% endif %} - {{ config.title }} -{% endblock %} - -{% block content %} -

{{ section.title }}

- - -{% endblock %} diff --git a/templates/macros/blog.html b/templates/macros/blog.html deleted file mode 100644 index 66bcd69..0000000 --- a/templates/macros/blog.html +++ /dev/null @@ -1,59 +0,0 @@ -{% macro sectionlisting(section) %} - - {{ self::postlist(section=section) }} -
-{% endmacro postlisting %} - -{% macro postlisting(posts) %} - - {% for post in posts %} - {{ self::display_post(post=post) }} - {% endfor %} -
-{% endmacro postlisting %} - -{% macro postlist(section) %} - {% set post_paths = self::recursive_visit(section=section) %} - {% set_global posts = [] %} - {% for path in post_paths | split(pat="&") %} - {% set clean_path = path | trim %} - {% if clean_path == "" %}{% continue %}{% endif %} - {% set post = get_page(path=clean_path) %} - {% set_global posts = posts | concat(with=post) %} - {% endfor %} - - {% for post in posts | sort(attribute="date") | reverse %} - {{ self::display_post(post=post) }} - {% endfor %} -{% endmacro %} - -{% macro recursive_visit(section) %} - {% if section.extra.include_posts == true %} - {% for page in section.pages %}{{ page.relative_path }}&{% endfor %} - {% for sub in section.subsections %} - {{ self::recursive_visit(section=get_section(path=sub)) }} - {% endfor %} - {% endif %} -{% endmacro %} - -{% macro display_post(post) %} - {% if not post.draft %} - - - - {{ post.title }} - -
- - {{ post.reading_time }} min read - Posted {% if post.extra.author %}by {{ post.extra.author }}{% endif %} - on {{ post.date }} - - - {% if post.tags %} - - {{ post.tags | join(sep=", ") }} - - {% endif %} - - {% endif %} -{% endmacro %} diff --git a/templates/macros/layout.html b/templates/macros/layout.html deleted file mode 100644 index 6f2081c..0000000 --- a/templates/macros/layout.html +++ /dev/null @@ -1,12 +0,0 @@ -{% macro navbar(config) %} - -{% endmacro navbar %} diff --git a/templates/macros/post.html b/templates/macros/post.html deleted file mode 100644 index 93b2461..0000000 --- a/templates/macros/post.html +++ /dev/null @@ -1,12 +0,0 @@ -{% macro render_toc(toc) %} -
    - {% for item in toc %} -
  • - {{ item.title }} - {% if item.children %} - {{ post::render_toc(toc=item.children) }} - {% endif %} -
  • - {% endfor %} -
-{% endmacro %} diff --git a/templates/post.html b/templates/post.html deleted file mode 100644 index 65c1b43..0000000 --- a/templates/post.html +++ /dev/null @@ -1,42 +0,0 @@ -{% extends "layout.html" %} -{% import "macros/layout.html" as layout %} -{% import "macros/post.html" as post %} - -{% block title %} - {% if page.title %}{{ page.title }} - {% endif %} - {{ config.title }} -{% endblock %} - -{% block content %} - « back -

{{ page.title }}

- {% if page.date or page.author %} - - Posted - {% if page.extra.author %}by {{ page.extra.author }}{% endif %} - on {{ page.date }} - - {{ page.reading_time }} min read - - {% endif %} - - {% if page.extra.toc and page.toc | length %} -
- table of contents - {{ post::render_toc(toc=page.toc) }} -
- {% endif %} - -
{{ page.content | safe }}
- -
- - End. - {% if page.taxonomies.tags %} - This post is tagged with: - {% for tag in page.taxonomies.tags %} - {% if loop.index0 > 0 %}, {% endif %} - {{ tag }} - {% endfor %} - {% endif %} - -{% endblock %} diff --git a/templates/rss.xml b/templates/rss.xml deleted file mode 100644 index 8e9f409..0000000 --- a/templates/rss.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - {{ config.title }} - {{ config.base_url | safe }} - {{ config.description }} - zola - {{ config.default_language }} - - {{ last_build_date | date(format="%a, %d %b %Y %H:%M:%S %z") }} - {% for page in pages %} - - {{ page.title }} - {{ page.date | date(format="%a, %d %b %Y %H:%M:%S %z") }} - {{ page.permalink | safe }} - - {% if page.summary %} - {{ page.summary | safe }} - Continue reading... - {% else %} - Read {{ page.title }}. - {% endif %} - - - {% endfor %} - - diff --git a/templates/tags/list.html b/templates/tags/list.html deleted file mode 100644 index 0d85e12..0000000 --- a/templates/tags/list.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "layout.html" %} - -{% block title %} - tags - {{ config.title }} -{% endblock %} - -{% block content %} -

tags

-

- {% for term in terms %} - {{ term.name }} - {% endfor %} -

-{% endblock %} diff --git a/templates/tags/single.html b/templates/tags/single.html deleted file mode 100644 index e2e45ac..0000000 --- a/templates/tags/single.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "layout.html" %} -{% import "macros/blog.html" as blog %} - -{% block title %} - articles under {{ term.name }} - {{ config.title }} -{% endblock %} - -{% block content %} - « back to tags -

articles under {{ term.name }}

-

- {{ blog::postlisting(posts=term.pages) }} - -

- click here for RSS feed -

-{% endblock %}