Uploading the current site in full so I can ignore it and start over

master
Lijero 2018-01-22 16:03:54 -08:00
parent e20191c01b
commit 581371b073
33 changed files with 8506 additions and 431 deletions

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "xexprs"]
path = xexprs
url = https://github.com/lijerom/xexprs

View File

@ -1,84 +0,0 @@
module RobotsTxt ( defaultRobotsTxt
, generateRobotsTxt
, forbidUrl
, forbidBotUrls
, withCrawlDelay
, withCanonicalDomain
, withSitemap
, usingDefaultSitemap
) where
type Seconds = Int
type DomainName = String
type Url = String
type UserAgent = String
data RobotsTxt = RobotsTxt
{ crawlDelay :: Seconds
, canonicalDomain :: Maybe DomainName
, sitemapLocation :: Maybe Url
, globalDisallows :: [Url]
, botDisallows :: [(UserAgent, [Url])]
}
defaultRobotsTxt :: RobotsTxt
defaultRobotsTxt = RobotsTxt
{ crawlDelay = 10
, canonicalDomain = Nothing
, sitemapLocation = Nothing
, globalDisallows = []
, botDisallows = []
}
forbidUrl :: Url -> RobotsTxt -> RobotsTxt
forbidUrl url cnf = cnf { globalDisallows = url : globalDisallows cnf }
forbidBotUrls :: (UserAgent, [Url]) -> RobotsTxt -> RobotsTxt
forbidBotUrls forbid cnf = cnf { botDisallows = forbid : botDisallows cnf }
withCrawlDelay :: Seconds -> RobotsTxt -> RobotsTxt
withCrawlDelay time cnf = cnf { crawlDelay = time }
withCanonicalDomain :: String -> RobotsTxt -> RobotsTxt
withCanonicalDomain domain cnf = cnf { canonicalDomain = Just domain }
withSitemap :: String -> RobotsTxt -> RobotsTxt
withSitemap url cnf = cnf { sitemapLocation = Just url }
usingDefaultSitemap :: RobotsTxt -> RobotsTxt
usingDefaultSitemap cnf = cnf { sitemapLocation = fmap (++ "/sitemap.xml") $ canonicalDomain cnf }
robotsTxtField :: String -> String -> String
robotsTxtField name value = name ++ ": " ++ value ++ "\n"
robotsTxtEmptyField :: String -> String
robotsTxtEmptyField name = name ++ ":"
globalUserAgent :: String
globalUserAgent = "*"
userAgentField :: UserAgent -> String
userAgentField = robotsTxtField "User-agent"
crawlDelayField :: Seconds -> String
crawlDelayField = robotsTxtField "Crawl-delay" . show
canonicalDomainField :: DomainName -> String
canonicalDomainField = robotsTxtField "Host"
disallowField :: Url -> String
disallowField = robotsTxtField "Disallow"
generateDisallowList :: [Url] -> String
generateDisallowList [] = robotsTxtEmptyField "Disallow"
generateDisallowList xs = foldl1 (++) $ map disallowField xs
generateBotDisallowList :: (UserAgent, [Url]) -> String
generateBotDisallowList (bot, urls) = userAgentField bot ++ generateDisallowList urls
generateRobotsTxt :: RobotsTxt -> String
generateRobotsTxt config = (userAgentField globalUserAgent)
++ (crawlDelayField $ crawlDelay config)
++ (maybe "" canonicalDomainField $ canonicalDomain config)
++ (generateDisallowList $ globalDisallows config)
++ (foldl1 (++) $ map generateBotDisallowList $ botDisallows config)

View File

@ -1,105 +0,0 @@
module SitemapXml
( ChangeFreq
, mkPriority
, defaultPriority
, defaultUrlData
, withPriority
, withLastMod
, withChangeFreq
, generateSitemapXml
) where
import Text.Printf (printf)
type Sitemap = [UrlData]
data ChangeFreq = CFNever
| CFYearly
| CFMonthly
| CFWeekly
| CFDaily
| CFHourly
| CFAlways
instance Show ChangeFreq where
show CFNever = "never"
show CFYearly = "yearly"
show CFMonthly = "monthly"
show CFWeekly = "weekly"
show CFDaily = "daily"
show CFHourly = "hourly"
show CFAlways = "always"
data Priority = Priority Int
instance Show Priority where
-- There is probably a better way to do this
show (Priority x) = printf "%.1f" (fromIntegral x / 10 :: Float)
mkPriority :: Int -> Priority
mkPriority x | x >= 0 && x <= 10 = Priority x
defaultPriority :: Priority
defaultPriority = mkPriority 5
data UrlData = UrlData
{ url :: String
, lastMod :: Maybe String
, changeFreq :: Maybe ChangeFreq
, priority :: Priority
}
defaultUrlData :: String -> UrlData
defaultUrlData url = UrlData { url = url, lastMod = Nothing, changeFreq = Nothing, priority = defaultPriority }
withPriority :: Int -> UrlData -> UrlData
withPriority x dat = dat { priority = mkPriority x }
withLastMod :: String -> UrlData -> UrlData
withLastMod x dat = dat { lastMod = Just x }
withChangeFreq :: ChangeFreq -> UrlData -> UrlData
withChangeFreq x dat = dat { changeFreq = Just x }
-- I know there are Xml generation libraries, but it's not worth their inclusion
-- over such a trivial application at this point
data Xml = Tag String [(String, String)] [Xml] | Data String
renderAttribute :: (String, String) -> String
renderAttribute (name, value) = name ++ "=\"" ++ value ++ "\""
xmlComment :: String
xmlComment = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
renderXml :: Xml -> String
renderXml (Data x) = x
renderXml (Tag name attrs body) = openTag
++ renderedBody
++ closeTag
where openTag = "<" ++ name ++ " " ++ attributes ++ ">"
attributes = unwords $ map renderAttribute attrs
renderedBody = foldl1 (++) $ map renderXml body
closeTag = "</" ++ name ++ ">"
tagNoAttrs :: String -> [Xml] -> Xml
tagNoAttrs name body = Tag name [] body
tagOneBody :: String -> Xml -> Xml
tagOneBody name body = tagNoAttrs name [body]
maybeList :: Maybe a -> [a]
maybeList Nothing = []
maybeList (Just x) = [x]
urlDataToXml :: UrlData -> Xml
urlDataToXml dat = tagNoAttrs "url" $ locTag ++ priorityTag ++ lastModTag ++ changeFreqTag
where locTag = [tagOneBody "loc" $ Data $ url dat]
priorityTag = [tagOneBody "priority" $ Data $ show $ priority dat]
lastModTag = maybeList $ fmap (tagOneBody "lastmod" . Data) $ lastMod dat
changeFreqTag = maybeList $ fmap (tagOneBody "changefreq" . Data . show) $ changeFreq dat
sitemapToXml :: Sitemap -> Xml
sitemapToXml = Tag "urlset" [("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9")] . map urlDataToXml
generateSitemapXml :: Sitemap -> String
generateSitemapXml sitemap = xmlComment ++ (renderXml $ sitemapToXml sitemap)

50
article.php Normal file
View File

@ -0,0 +1,50 @@
<?php
$slug = $_GET["slug"];
$servername = "localhost";
$username = "local";
$password = "";
$article_query = "SELECT * FROM articles WHERE slug = ?";
//$keyword_query = "SELECT * FROM keywords WHERE id = ?";
?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta charset="utf-8" />
<meta author="<?php echo $article['author'] ?>" />
<meta name="description" content="<?php echo $article['description'] ?>" />
<meta name="keywords" content="<?php echo implode(',', $keywords ?>" />
<meta name="robots" content="index,follow" />
<title><?php echo $article['title'] ?> - Lijero</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="/favicon.png" rel="icon" type="image/png" />
<link href="/res/common.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
_paq.push(["setCookieDomain", "*.lijero.co"]);
_paq.push(["setDomains", ["*.lijero.co"]]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//p.lijero.co/";
_paq.push(['setTrackerUrl', u+'foo']);
_paq.push(['setSiteId', '1']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'foo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
</head>
<body>
<nav>
<div id="navbrand">Lijero</div>
<ul>
<?php foreach ($navbar as $navitem) { ?>
<li><a href="<?php echo $navitem['url'] ?>"><?php echo $navitem['name'] ?></a></li>
</ul>
</nav>
<article>
<header>
<h1>

View File

@ -0,0 +1,187 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta charset="utf-8" />
<meta name="author" content="Lijero" />
<!-- <meta name="description" content="" /> -->
<meta name="keywords" content="Lijero,code,operating system,distributed,network,resource graph,abstraction" />
<meta name="robots" content="index,follow" />
<title>Beyond Operating Systems - Lijero</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="/favicon.png" rel="icon" type="image/png" />
<link href="/res/common.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
var _paq = _paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
_paq.push(["setCookieDomain", "*.lijero.co"]);
_paq.push(["setDomains", ["*.lijero.co"]]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//p.lijero.co/";
_paq.push(['setTrackerUrl', u+'foo']);
_paq.push(['setSiteId', '1']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'foo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
</head>
<body>
<nav>
<div id="navbrand">Lijero</div>
<ul>
<li><a href="/">Home</a></li>
</ul>
</nav>
<article>
<header>
<h1>Beyond Operating Systems - Abstracting Over Networks</h1>
<div class="metadata">
<span><img src="/res/icon/person.svg" alt="Author" /> <span class="author"><a href="https://lijero.co/about/lijero">Lijero</a></span></span>
<span><img src="/res/icon/clock.svg" alt="Date" /> Posted 2017-10-06</span>
</div>
</header>
<h2>Introduction</h2>
<p>
I've come to get my crazy idea smashed apart. Or open an innovative discussion! Whatever it is, I don't wanna waste your time so I'll be brief. Let me know if anything needs clarification, since I'm shrinking a couple notebooks into one article.
</p>
<h3>Programs running on the internet itself</h3>
<p>
I want to write software for the whole internet! That can mean a lot of things, though:
<ul>
<li>Websites without a host</li>
<li>Multiplayer games and apps without even <em>thinking</em> about servers</li>
<li>Easy distributed stuff like cryptocurrencies</li>
</ul>
</p>
<p>
Operating systems mean we can write software for <em>any</em> computer but I want to write software for <em>every</em> computer at once! A <strong>globally distributed operating system</strong>.
</p>
<h3>Building up to a global OS</h3>
<p>
It's gonna take a lot of layers of abstraction. Bear with me, I'll get there eventually!
</p>
<h2>Step 1: The Resource Graph</h2>
<p>
If you're going to write a distributed operating system, it better <strong>not matter where data comes from</strong>. So <strong>unify every resource</strong>, from memory to files to HTTP calls, into a <em>resource graph</em>. That said, you can't make assumptions about your surroundings either: <strong>implicit dependencies have got to go</strong>.
</p>
<h3>Unifying resources</h3>
<p>
We still need to know what data is, which can be pretty tough when you don't know where it's coming from. The solution is an <strong>extremely strong type system</strong>. The type system tells software what data actually is. That said, different resources have different properties, so this has to be expressed in the type system as well.
</p>
<h3>Killing implicit dependencies</h3>
<p>
This is where the resource graph comes in. A graph is just a general way to structure data. It's basically a generalized filesystem. The important difference is that <strong>there is no root</strong>. We get data around by building, rebuilding, and passing resource graphs, rather than ACL on a general filesystem or whatever. We pass around references.
</p>
<h3>Programming with a resource graph</h3>
<p>
Today's languages are not well-suited to this model of data. Neither are computers: you can't have a pointer to an HTTP resource. Also, it needs to be enforced, so RIP native binaries. Not that you could have them anyway, since the internet runs on a loot of architectures. Instead, you'd need a bytecode interpreter that can actually handle it all natively.
</p>
<p>
Also, I swear I am not a Lisp shill and I had no intention of it, but Lisp happens to be really good at dealing with linked data structures. It'd probably be really convenient for dealing with this sort of thing. Though this system is strongly typed, unlike Lisp.
</p>
<h3>There's more to resources than CRUD</h3>
<p>
There needs to be an actual way to implement all these fancy types of nodes. And how can we not care about the source of something being HTTP if we need to make a query? The solution is simple: <strong>make every node a computation</strong>. And by computation I mean closure.
</p>
<p>
I mean, how did you <em>think</em> the nodes were implemented? Most nodes are actually a procedure to fetch the requested content. But you can also make nodes with inputs and outputs, such as an HTTP query. Of course, we need to know where we're getting the data from, so that must have been put in earlier. The resources with that information have been enclosed in the node.
</p>
<p>
Nodes are functions. They're partially applied with a portion of the graph they require to make closures. In fact, <strong>functions are nodes too</strong>. So are all processes. You pass in a parameter graph and get back data.
</p>
<p>
Now I hope it makes sense how we can have all the features of a kernel without syscalls. Your malloc or whatever is inclosed with the relevant information, including any syncronization references.
</p>
<h2>Step 2: Computational Economy</h2>
<p>
So what if we <strong>assign an expense to a function</strong>? We can count instructions, give them different expenses, and sum them up to get a final price. We can calculate the range of potential prices by calculating branches as lumps and adding them each time a branch is taken. From here, we can extend it to the cost of data (e.g. memory) by calculating <strong>quantity of data over computational time</strong>. Bandwidth costs are obvious too. This is how you can implement schedulers, when you expose the interpreter as a resource.
</p>
<h4>What about the halting problem?</h4>
<p>
Totality proofs (manual or automatic), and relating expense to the input. Where it cannot be proven, the maximum expense can be considered infinite. In many of those cases, it would make sense to put an <strong>upper bound on the amount you're willing to pay to run a function</strong>.
</p>
<h3>Paying for our remote access</h3>
<p>
Servers can also assign an expense to queries if you modified e.g. HTTP to do it. <strong>HTTP is just a kind of RPC anyway</strong>, and it now behaves exactly like one in our resource graph. Now you can pay them for your access to their resource graph!
</p>
<strong>We've now turned computational expense into a currency!</strong>
<p>
How cryptocurrencies are implemented is out of the scope of this article, but we can now turn this into one, and trade our currency for computation.
</p>
But to continue, if accessing someone else's resources has a cost, we should probably be <em>paying</em> for it, right? Paying for goods and services. Seems familiar. Maybe our "money" really is just that-- a currency. Are y'all familiar with cryptocurrencies? Because we're well on our way to making one. Explaining how blockchains like bitcoin work is waay out of the scope of this post (or perhaps not-- but at any rate, it's too long to explain in this one), but to SUPER summarize it, we can use cryptographic mAgIc to sell portions of transactions and stuff with cryptographic proof, tl;dr a distributed currency. I'll have to explain how it works, and how you can make contracts to prevent scams and stuff, and how to deal with redundant computation in a different post, because you have no idea just how much further I can push this (i.e. I don't have time for that sort of digression).
The end result is that your pair of computers can trade resources and do all sorts of crazy stuff all beneath the nose of the program itself. This can be generalized to a more sensible system by decoupling the e.g. local per-instruction expense and currency to allow competition between suppliers, but that's pretty complicated too, and I want to stick to the realm of abstractions, rather than defining the economic system. Anyway, from there you can just extend this abstraction over an entire network of computers, and buy/sell resources as needed. You're probably seeing a lot of issues at this point (e.g. what if the other computers lie, what if they drop my data, what about latency, what about network partitions, what if they steal my data, how do I deal with all of these transactions in a performant matter), but don't worry, I'll get to them later. Actually, there are going to be a /lot/ of places coming up where I'll have to get to it later, so I'm going to stop giving this notice, but I will cover them. Also, if you're thinking, "this keeps sounding less and less like osdev", you're right. I'm no longer strictly discussing operating systems-- I've generalized the concept of an operating system, which abstracts over hardware and other such things, to an entire network.
Now that's a pretty big claim, but none of what I've said so far is all that impressive. Most of us have enough power on our computers not to need to buy it, and just doing these tasks the old-fashioned way is a heck of a lot easier for these benefits so far (though before I got so far out, the ideas still in the realm of typical operating systems is more justification than a lot of hobby OSes). The thing is, I'm claiming to abstract over the internet, but really all I've talked about is loaning resources and paying for data. Applications haven't changed that much, only their execution platform, and a couple of conveniences. For example, your HTTP server still holds all your data, you're just getting paid for holding it (though you can pay other people to act like a CDN). The issue is that while the computation is distributed and that space can be loaned, data is still fundamentally centralized. Sure, it's over a bunch of computers, but there's no concept of shared data. Your applications can run all <em>over</em> the internet, but not <em>on</em> it.
<h2>Running <em>ON</em> the Internet -- Fully distributed applications</h2>
Now we're finally at my point. What I want is to be able to write fully distributed multi-user applications in a similar way to how we write standard applications now. There shouldn't be a server or host or central authority, you shouldn't have to deal with figuring out where data is stored, you shouldn't have to figure out the fine details of protocols, and such things. Publishing pages or files Web 1.0-style shouldn't require any hosting, and <em>all</em> data should receive the benefits of torrenting automatically. Interactive content (web 2.0, IRC, etc) should behave similarly. Games shouldn't need to worry about hosting (all multiplayer games should be as easy as LAN hosting is today, and large servers should be a hell of a lot cheaper i.e. free). A distributed data store.
<h2>Getting back to details</h2>
If you can't think of a billion potential issues with this, I'm disappointed in you. But don't worry, I've reached peak abstraction, and now I can start working my way back down into details and issues. I'm probably going to go from easier issues to harder issues and low-level issues to high-level issues, just fyi. I know this is written like an FAQ but I keep building on important details here.
* Aren't interpreters slow? How is it a good idea to run your entire operating system on them?
They are typically slow, but as they're the core of the entire everything, a lot of optimization would go into it. It'd probably be rather low-level bytecode, and have an extremely efficient interpreter. Some degree of JITting would probably occur, when there is very high confidence it won't open up a bug. Since resources are managed in a graph and implicit dependencies are impossible, I'd assume people could take advantage of these properties to achieve an extremely high level of parallelism, like they do in functional programming languages.
* How would it be safe to run unknown code on your computer?
It's not, but you're probably doing it right now with your browser. There's the obvious distinction between going to trusted websites and getting pushed data from strangers, though. There's some inevitable risk in any internet connection, and the best you can do is minimize that risk. I would try to keep the inner interpreter extremely simple and small, perhaps even going as far as to formally verify it, to prevent exploits; JITting should be used with extreme caution; I would sandbox processes pushed to me when possible; and I would also try to take the precautions used by OSes such as OpenBSD. Overall though, I'm reasonably confident in it, and the complete lack of implicit dependencies makes it a hell of a lot more secure than running random executables, even sandboxed ones, and brings it closer to e.g. JS. The language wouldn't even deal with numeric pointers (to real memory, not as in the concept), to prevent accidental pointer arithmetic bugs.
<h4>How do I access raw resources from the interpreted language?</h4>
The interpreter would pass in operations for raw resource access into the boot program, which can then create closures wrapping these resources (e.g. a memory allocator, a partition reader, other device wrappers) and keep building abstractions on these, with only the abstractions being included in the resource graph for normal programs. How these raw resources are provided is an implementation detail. It could potentially involve bootstrap stages and assembly output.
<h4>Okay, well how do these abstractions work? <strong>What is a graph node anyhow?</strong></h4>
Each node is essentially a function call, though most of the actual function calls would be optimized away. You pass in a graph with the correct data types, and assign the result to another local graph node. The closures are actually more like partially applied functions in this sense, since the graph has to be explicitly passed in and must have exactly the required functions and nothing more, but I call them closures because it "captures" the resource access primitives from the creator, and then gets given actual input later. Resources like an HTTP call are essentially just lazily-evaluated procedures.
<h4>How is it performant to have a program distributed over multiple computers? <strong>How does the network manage latency and throughput?</strong></h4>
Usually, it isn't. Loaning resources isn't the point, it's just a necessary abstraction to build the rest of the network, for things like contracts, and managing the distributed data store. Usually, the actual computation and its related data will be transferred as a block (lazily, of course) to the actual place of execution, and only independent batch jobs will be transferred. A computer would rarely actually pay for a computation unless necessary (think swap space), and will do computations locally when possible, and local-initiated computations always take priority over sold computations. There are only two purposes other than for internal infrastructure and massively distributed computation projects: conserving battery life, and accessing remote resources. Often it doesn't make sense to download large portions of a database when the content you actually want is a lot smaller, so you just pay someone who already has it to do it for you. If this is a common case and it gets overwhelmed, its own price goes up until someone else finds it cheaper to grab the data than pay for it, and then you have two cheap servers. They don't have to maintain a clone of the database obviously, but in most cases, for a commonly-accessed resource, it makes sense because you can resell (seed) the data yourself, or you'll want to retrieve it again and have it there. This is how static (as opposed to stateful, not dynamic) data propagates through the network. You can tell whether something is common by announcing you have it, and holding onto it. This means that the more popular a resource is, the faster and cheaper it becomes to retrieve because more people have it. If it becomes less popular, or otherwise overhosted, people will automatically drop it because it's no longer profitable to host. Additionally, the more people host something, the more likely there is a version close to you, which reduces latency. This is especially true of geographically popular data. Beyond that, it is trivial to chunk data, so that the end users receive <strong>all data like a bittorrent</strong>. Through these mechanisms, <strong>static data would be much faster than the normal internet, since all data behaves like a torrent or CDN.</strong> Stateful data still receives many of these benefits, but that'll have to wait for later.
I had to take a break from writing this post, so hopefully I don't miss anything. I probably will, having lost my train of thought now.
* Isn't it expensive to track computations like that / CPU cache &amp; branch prediction?
You can calculate the length of each block in advance, and only need to add the sum of the block to the total when a branch is taken. Locally initiated code could under some circumstances be free and not need to be tracked at all.
* Can this have any <em>benefit</em> to security, as far as local programs go?
Isolation of programs &amp; capability-based security: no implicit dependencies or global resource graph to exploit. You can't traverse e.g. the whole filesystem because the concept of "the whole filesystem" isn't meaningful.
<h2>The implementation of distributed state</h2>
Oh lord. Now I have to move onto the implementation of distributed state. I'm not really looking forward to this, since everything I've said so far is just the tip of the iceberg as far as details go. Most of my countless pages of notebook are trying to work around the insane difficulties of building a general case for distributed applications. Can't I just stick to hype? Shit. Man, and that's not even counting explaining the usual blockchain problems.
<h3>The guarentees of a distributed system</h3>
What we're essentially looking at is an extremely complex internet overlay network implemented on top of the operating system I've described so far, to provide guarantees about data. We have opened the gates of hell. I suppose I should start off by listing the properties that such a network needs to be able to have:
<ul>
<li> The typical cryptographic guarantees: confidentiality, integrity, availability, and non-repudiation</li>
<li> Agreement upon the order in which things occurred *with low latency* (FUCK the PACELC theorem). Sometimes a partial ordering is acceptable</li>
<li> Prove that things actually happened to peers who did not observe it (this is incredibly complex if you don't want to use blockchain)
</li><li> Separation of identity / pseudonymity / persistent identification: actually this is by far the easiest thing here
</li><li> The ability to locate and retrieve public data
</li><li> Anonymity (note: I'm not willing to even think about anonymity networks. I figure this is separation of identity + layering connections over I2P or some other existing anonymity network-- I2P is just built for this sort of thing though).
</li><li> Privacy of the data
</li><li> Provable secrets such as e.g. player position in an FPS
</li><li> Reforming the network in the case of a partition
</li><li> The ability to update the program while maintaining the same data store
</li><li> Guaranteeing consistent data across the entire network
</li><li> Preventing lying about data
</li><li> Separation of semantic units of data-- only perform necessary replication of calculations, and only providing the guarantees necessary for a particular block of data
</li><li> Resilience against censorship, malicious firewalls, DDOS, and such
</li><li> Continued functionality in high-latency and/or low-bandwidth environments, and unreliable connections
</li><li> Protection against <em>spam</em> and cheaters
</li><li> Multi-modality for when server architectures just work best for performance
</li><li> Prevention against data loss, especially for the ability to do stuff like long-term remote file hosting
</li><li> Plausible deniability</li>
</ul>
</article>
<footer>
<div class="license"><a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="/res/cc-by-sa-small.png" /></a> This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International License</a>.</div>
<div>Open Iconic — <a href="https://www.useiconic.come/open">www.useiconic.com/open</a> / MIT Licensed, attribution optional</div>
<div>This page is friendly to text browsers.</div>
</footer>
</body>
</html>

1548
includes/parsedown.php Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<!-- Uses Open Iconic: MIT licenses, attribution optional licenses. -->
<!-- This page is friendly to text browsers. -->
<head>
<meta charset="utf-8" />
@ -14,24 +16,34 @@
<link href="/favicon.png" rel="icon" type="image/png" />
<link href="/res/common.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
var _paq = _paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
_paq.push(["setCookieDomain", "*.lijero.co"]);
_paq.push(["setDomains", ["*.lijero.co"]]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//p.lijero.co/";
_paq.push(['setTrackerUrl', u+'foo']);
_paq.push(['setSiteId', '1']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'foo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
</head>
<body>
<nav>
<div id="navbrand">Lijero</div>
<ul>
<li><a href="/">Home</a></li>
<li>Music</li>
<li>Games</li>
<li>About</li>
</ul>
</nav>
<article>
<header>
<h1>Test Content</h1>
<div class="metadata">
<span><img src="/res/icon/person.svg" alt="Author" /> <span class="author"><a href="https://lijero.co/about/lijero">Lijero</a></span></span>
<span><img src="/res/icon/clock.svg" alt="Date" /> Posted 2017-09-29 / Updated 2017-10-02</span>
</div>
</header>
<h2>Summary</h2>
<div class="aside quote">
@ -48,9 +60,15 @@ but this often comes at the cost of readability. My goal with this website is to
<p>I have a bunch of content already, but I think a third paragraph would be nice too. In addition, this lets me intract with the website through scrolling, which could possibly make a difference, though I can't say for sure. Anyway, this content should help with both of these issues.</p>
</article>
<footer>
<div class="license"><a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="/res/cc-by-sa-small.png" /></a> This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International License</a>.</div>
<div>Open Iconic — <a href="https://www.useiconic.come/open">www.useiconic.com/open</a> / MIT Licensed, attribution optional</div>
<div>This page is friendly to text browsers.</div>
<div class="metadata">
<span><img alt="Author" src="//lijero.co/res/icon/person.svg" /> Lijero</span>
<span><img alt="Updated" src="//lijero.co/res/icon/clock.svg" /> 2017-12-16</span>
<div class="license">
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">
<img alt="This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License" style="border-width:0" src="/res/cc-by-sa-small.png" />
</a>
</div>
</div>
</footer>
</body>
</html>

79
index.xhtml.old Executable file
View File

@ -0,0 +1,79 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<!-- Uses Open Iconic: MIT licenses, attribution optional licenses. -->
<!-- This page is friendly to text browsers. -->
<head>
<meta charset="utf-8" />
<meta name="author" content="Lijero" />
<!-- <meta name="description" content="" /> -->
<meta name="keywords" content="Lijero,music,code,producer,games,website" />
<meta name="robots" content="index,follow" />
<title>Lijero</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="/favicon.png" rel="icon" type="image/png" />
<link href="/res/common.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
var _paq = _paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
_paq.push(["setCookieDomain", "*.lijero.co"]);
_paq.push(["setDomains", ["*.lijero.co"]]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//p.lijero.co/";
_paq.push(['setTrackerUrl', u+'foo']);
_paq.push(['setSiteId', '1']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'foo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
</head>
<body>
<nav>
<div id="navbrand">Lijero</div>
<ul>
<li><a href="/">Home</a></li>
<li>Music</li>
<li>Games</li>
<li>About</li>
</ul>
</nav>
<article>
<header>
<h1>Test Content</h1>
</header>
<h2>Summary</h2>
<div class="aside quote">
<div class="quote-content"> To make an apple pie from scratch, you must first invent the universe. </div>
<div class="author">~ Carl Sagan</div>
</div>
<p>NOTICE: I have some real content located at <a href="https://lijero.co/articles/beyond-operating-systems">Beyond Operating Systems</a>, though it is heavily WIP.
</p>
<p>
This is some <a href="//example.com">test content</a>. The purpose of this content is to demonstrate the readability of small-width, large-margined, well-spaced, large text. A lot of websites are extremely compact,
but this often comes at the cost of readability. My goal with this website is to provide an entirely different and more attractive user experience.
</p>
<h2>Lorem Ipsum</h2>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus</p>
<h2>Extra Content</h2>
<p>I have a bunch of content already, but I think a third paragraph would be nice too. In addition, this lets me intract with the website through scrolling, which could possibly make a difference, though I can't say for sure. Anyway, this content should help with both of these issues.</p>
</article>
<footer>
<div class="metadata">
<span><img alt="Author" src="//lijero.co/res/icon/person.svg" /> Lijero</span>
<span><img alt="Updated" src="//lijero.co/res/icon/clock.svg" /> 2017-12-16</span>
<div class="license">
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">
<img alt="This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License" style="border-width:0" src="/res/cc-by-sa-small.png" />
</a>
</div>
</div>
</footer>
</body>
</html>

77
menukill.xhtml Executable file
View File

@ -0,0 +1,77 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<!-- Uses Open Iconic: MIT licenses, attribution optional licenses. -->
<!-- This page is friendly to text browsers. -->
<head>
<meta charset="utf-8" />
<meta name="author" content="Lijero" />
<!-- <meta name="description" content="" /> -->
<meta name="keywords" content="Lijero,music,code,producer,games,website" />
<meta name="robots" content="index,follow" />
<title>Lijero</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="/favicon.png" rel="icon" type="image/png" />
<link href="/res/common.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
var _paq = _paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
_paq.push(["setCookieDomain", "*.lijero.co"]);
_paq.push(["setDomains", ["*.lijero.co"]]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//p.lijero.co/";
_paq.push(['setTrackerUrl', u+'foo']);
_paq.push(['setSiteId', '1']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'foo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
</head>
<body>
<nav>
<div id="navbrand">Lijero</div>
<ul>
<li><a href="/">Home</a></li>
<li>Music</li>
<li>Games</li>
<li>About</li>
</ul>
</nav>
<article>
<header>
<h1>Test Content</h1>
</header>
<h2>Summary</h2>
<div class="aside quote">
<div class="quote-content"> To make an apple pie from scratch, you must first invent the universe. </div>
<div class="author">~ Carl Sagan</div>
</div>
<p>
This is some <a href="//example.com">test content</a>. The purpose of this content is to demonstrate the readability of small-width, large-margined, well-spaced, large text. A lot of websites are extremely compact,
but this often comes at the cost of readability. My goal with this website is to provide an entirely different and more attractive user experience.
</p>
<h2>Lorem Ipsum</h2>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus</p>
<h2>Extra Content</h2>
<p>I have a bunch of content already, but I think a third paragraph would be nice too. In addition, this lets me intract with the website through scrolling, which could possibly make a difference, though I can't say for sure. Anyway, this content should help with both of these issues.</p>
</article>
<footer>
<div class="metadata">
<span><img alt="Author" src="//lijero.co/res/icon/person.svg" /> Lijero</span>
<span><img alt="Updated" src="//lijero.co/res/icon/clock.svg" /> 2017-12-16</span>
<div class="license">
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">
<img alt="This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License" style="border-width:0" src="/res/cc-by-sa-small.png" />
</a>
</div>
</div>
</footer>
</body>
</html>

View File

@ -18,6 +18,10 @@ nav {
font-style: italic;
}
nav li {
text-indent: 0;
}
nav ul {
list-style: none;
}
@ -31,9 +35,9 @@ article {
}
p {
text-align: justify;
text-justify: distribute;
text-indent: 4em;
/* text-align: justify;
text-justify: distribute;*/
text-indent: 2em;
}
article h1 {
@ -48,6 +52,10 @@ article h3 {
font-size: 20px;
}
li {
text-indent: 1em;
}
a {
text-decoration: none;
color: #5050B0;
@ -91,6 +99,7 @@ footer {
.license img {
display: inline-block;
width: initial;
vertical-align: bottom;
}
@ -101,68 +110,29 @@ footer {
}
}
@media screen and (max-width: 1200px) {
nav {
margin: auto;
padding: 0;
text-align: center;
}
nav {
margin: auto;
padding: 0;
text-align: center;
}
nav ul {
padding: 0;
}
nav ul {
padding: 0;
}
nav li {
margin: 0;
display: inline-block;
}
nav li {
margin: 0;
display: inline-block;
}
@media screen and (min-width: 700px) {
article {
padding: 30px 80px;
padding: 0 80px;
min-width: 25em;
max-width: 30em;
max-width: 33em;
}
article h1 {
margin-left: -20px;
}
}
@media screen and (min-width: 1200px) {
nav {
max-width: 15%;
float: left;
padding: 20px 45px 40px 40px;
margin-top: 10px;
border-left: 3px solid;
}
nav span {
padding-left: 20px;
}
nav ul {
margin-left: 20px;
}
nav li {
border-bottom: 1px solid #ccc;
padding: 3px;
}
nav ul li:last-child {
border-bottom: none;
}
.aside {
position: relative;
left: 60%;
float: right;
margin-left: 50%;
max-width: 50%;
}
}

171
res/common.css.old Normal file
View File

@ -0,0 +1,171 @@
body {
display: block;
margin: 0;
font-family: sans-serif;
}
nav {
font-weight: 400;
font-size: 25px;
letter-spacing: 2px;
color: #404040;
}
#navbrand {
font-weight: bold;
font-size: 50px;
color: black;
font-style: italic;
}
nav ul {
list-style: none;
}
article {
margin: auto;
line-height: 1.5em;
letter-spacing: .05em;
font-size: 18px;
color: #303030;
}
p {
/* text-align: justify;
text-justify: distribute;*/
text-indent: 4em;
}
article h1 {
font-size: 30px;
}
article h2 {
font-size: 25px;
}
article h3 {
font-size: 20px;
}
li {
text-indent: 1em;
}
a {
text-decoration: none;
color: #5050B0;
}
a:hover {
color: #8080A0;
}
nav a {
color: inherit;
}
.quote-content::before {
content: url("/res/icon/double-quote-serif-left.svg");
}
.quote-content {
font-style: italic;
}
.quote-content::after {
content: url("/res/icon/double-quote-serif-right.svg");
}
.metadata {
font-size: 15px;
}
.metadata img {
width: 15px;
}
footer {
padding: 10px;
font-size: 10px;
position: relative;
bottom: 0;
text-align: center;
}
.license img {
display: inline-block;
width: initial;
vertical-align: bottom;
}
@media screen and (max-width: 600px) {
article {
padding: 5px;
margin: 0;
}
}
@media screen and (max-width: 1200px) {
nav {
margin: auto;
padding: 0;
text-align: center;
}
nav ul {
padding: 0;
}
nav li {
margin: 0;
display: inline-block;
}
}
@media screen and (min-width: 700px) {
article {
padding: 30px 80px;
min-width: 25em;
max-width: 30em;
}
article h1 {
margin-left: -20px;
}
}
@media screen and (min-width: 1200px) {
nav {
max-width: 15%;
float: left;
padding: 20px 45px 40px 40px;
margin-top: 10px;
border-right: 3px solid;
}
nav span {
padding-left: 20px;
}
nav ul {
margin-left: 20px;
}
nav li {
border-bottom: 1px solid #ccc;
padding: 3px;
}
nav ul li:last-child {
border-bottom: none;
}
.aside {
position: relative;
left: 60%;
float: right;
margin-left: -50%;
max-width: 50%;
}
}

BIN
resume.docx Normal file

Binary file not shown.

BIN
resume.odt Normal file

Binary file not shown.

63
resume.xhtml Normal file
View File

@ -0,0 +1,63 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<!-- Uses Open Iconic: MIT licenses, attribution optional licenses. -->
<!-- This page is friendly to text browsers. -->
<head>
<meta charset="utf-8" />
<meta name="author" content="Lijero" />
<meta name="robots" content="index,follow" />
<title>Lijero - Projects</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="/favicon.png" rel="icon" type="image/png" />
<link href="/res/common.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
var _paq = _paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
_paq.push(["setCookieDomain", "*.lijero.co"]);
_paq.push(["setDomains", ["*.lijero.co"]]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//p.lijero.co/";
_paq.push(['setTrackerUrl', u+'foo']);
_paq.push(['setSiteId', '1']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'foo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
</head>
<body>
<nav>
<div id="navbrand">Lijero</div>
<ul>
<li><a href="/">Home</a></li>
</ul>
</nav>
<article>
<header>
<h1>Projects</h1>
</header>
<h2>Current Projects</h2>
<h3>The Switte Programming Language</h3>
<p>A programming language based on context-sensitive grammar production rules, derived from ordered linear dependent type theory.</p>
<h3>Switte Rules</h3>
<p>A rule processing engine + transactional database.</p>
<h2>Planned projects</h2>
<h3>SwitteOS</h3>
<p>An operating system based on the Switte programming language.</p>
<h3>SwitteNet</h3>
<p>A distributed overlay network.</p>
</article>
<footer>
<div class="metadata">
<span><img alt="Author" src="//lijero.co/res/icon/person.svg" /> Lijero</span>
<span><img alt="Updated" src="//lijero.co/res/icon/clock.svg" /> 2018-01-19</span>
</div>
</footer>
</body>
</html>

148
resume2.txt Normal file
View File

@ -0,0 +1,148 @@
Fluent with essential programming tools:
* I use Git or another version control system for all of my projects, and can effectively use its features, including branching and merging (https://github.com/lijerom/), also an understanding of semantic versioning
* I have used IDEs including Visual Studio and Eclipse, and configurable editors such as Emacs
* I know how to use command-line toolchains and manually configure project builds (GNU, Stack)
* I can efficiently and effectively use documentation to fill holes in my knowledge when necessary
* Familiar with continuous integration services such as Jenkins (https://ci.lijero.co)
* Efficient reporting and management using bugtrackers such as Mantis and Github Issues
* Microsoft Office, Word, and Excel of course! (in addition to LibreOffice)
Essential systems administration knowledge:
* Windows, Linux (esp. the Debian family) on the desktop and server, FreeBSD (basic familiarity w/ use and its model)
* Nginx (HTTP server & proxy, serves lijero.co), Bind9 (DNS, I run my own authoritative server for lijero.co), Charybdis (IRCd, formerly ran one for my friends), OpenSSHd (for myself, and formerly another two administrators), MySQL/MariaDB (basic familiarity), Murmur (mumble, formerly, for friends), FTP over SSH (I used to use it for file transfers) with my servers and VPSes
* Use an EDCHE-384 manually generated and signed via Let's Encrypt (https://lijero.co), w/ DNS CAA, HSTS (preloaded), OCSP must staple as a certificate extension -- an A+ rating on SSLLabs -- https://www.ssllabs.com/ssltest/analyze.html?d=lijero.co&latest
* Can configure iptables or other firewalls
* Understand how kernels (microkernels and monolithic kernels, exokernels), filesystems, network stacks, memory managers, schedulers, thread priorities, signals, interrupts, system services, kernel modules, program loaders, swap, paging, and other such features work from my own toy operating systems! (though I've only implemented a few of these things-- a basic kernel, file system, and memory manager)
* Basic load balancing techniques, content delivery network use, caches, semantic URLs
* Fundamental knowledge regarding databases: basic SQL, relational algebra, ACID, transactions, CAP theorem, PACELC theorem, CRUD
Familiarity with essential internet protocols:
* A basic understanding of IP and UDP, and a stronger understanding of TCP
* I understand background behind TLS(/SSL) but not the actual protocol details (I wanted to implement TLS and TCP, but never did)
* I have written HTTP 1.0 client libraries and servers for fun (and I understand how HTTP/2 works, though not enough to implement it)
* HTTP interface design techniques like REST w/ JSON and XML, HTTP functions
* Though it's not a protocol, remote procedure calls as a concept
* An IRC client+bot from scratch capable of all basic functions
* FTP and how it functions, as little as it's used nowadays
and the less essential ones...
* I wrote portions of a Minecraft server a couple years back using reverse-engineered protocol documentation, but not enough to be useful for gameplay (http://wiki.vg/Protocol)
* I wrote internal networking functions for my own Minecraft clone using both TCP and UDP (and that's when I discovered just how unreliable UDP was!)
* Various toy protocols I wrote, eg. a chat protocol
Strong theoretical background:
* Programming language development is my main hobby
* Firm grasp of type theory (polymorphic, dependent, linear, and non-commutative varieties-- homotopy, not so much), sequent calculus, lambek calculus
* Firm grasp of formal logic via type theory thanks to computational trinitarianism
* Basic background with category theory, albeit mainly through Haskell, and again, computational trinitarianism
* Competent with functional and object-oriented abstractions and design patterns
* In case you're running a keyword filter: YES I know recursion, loops, iteration, collections, maps (dictionaries), filtering, objects, classes, subtyping polymorphism, inheritance, interfaces, abstract classes, generics, lists, arrays, pointers, sets, multisets, stacks, trees, graphs, optionals, options, tuples, eithers, zippers, continuations (somewhat), strings, characters, integers (byte, ubyte, short, ushort, int, uint, long, ulong, bignum), decimals (float, double, bigdecimal), fixed-points, inductive types, coinductive types, lazy/eager evaluation, booleans, boolean algebra, records, unions, catamorphisms, isomorphisms, functors, monads, monoids, traversables, applicatives, foldables, semigroups, arrows, lenses, continuation-passing style, exceptions, coroutines, green threads, normal threads, mutexes, cooperative multitasking, messages, locks, atomic references, thread pools, reentrancy, thread-local storage, immutability, reference counting, garbage collection, pattern matching, category, vertical types, fixpoints, LUBs, promises, etc
* Understand how CPUs are designed and implemented (I built a 16-bit von-neumann stack-based CPU in Minecraft, and proceeded to design a real-life one on paper, though it has never been implemented)
* Linguistics (including artificial language construction) is another hobby of mine, and you wouldn't believe how often it comes up!
* Formal languages and grammar in terms of production rules
* Object-oriented, (purely) functional, imperative/procedural, reactive
Programming languages:
* Java (I write most of my projects in this, Robotics club), C# (an XNA platformer a couple years back, a Minecraft clone using the Unity game engine-- most of my Java knowledge is transferrable too)
* Haskell (used to write programming languages, parsers, and projects that don't require a lot of state or IO)
* Racket & Chicken Scheme, dialects of Lisp, Untyped Lambda Calculus (I used it often earlier on, including a web server, XHTML/XML/SVG generation DSL, and it sat right in the core of my operating system-- lambda calculus isn't a programming language obviously but it's related-- and I still use Racket Scribble for documentation)
* x86 assembly (used in a couple of essential components of my operating system, and used to make a Forth implementation)
* Forth (used in conjunction with x86 assembly to bootstrap itself, as is Forth tradition, but no real programs once I had it)
* Rust (used to write an HTML/XML parser and my Minecraft server implementation, and will likely be used again in the future)
* (X)HTML(5), CSS, SQL, PHP (used to build a webcomic site for a friend in middle school before the project was cancelled, a basic hierarchical board called "thread", and my own (incomplete) site, though it's not very technologically impressive thanks to its deliberately minimalist design (https://lijero.co))
* Prolog (I wrote a good chunk of an implementation of one, though I never finished, and have not used it for any real projects)
* C (portions of the operating system, the VM for that CPU I designed but never built)
* The yet-unnamed programming language I am building right now! (derived from non-commutative linear logic, w/ influences from Haskell, Rust, Lisp, and Forth)
Former projects
===============
Languages
* HTML, XML, SVG parsers and generators, DSLs
* A dozen lisp and lambda calculus implementations (at least one in every language I've ever used)
* An indirect-threaded Forth implementation in x86 assembly
* Reflection-based implementation of the reactive programming paradigm for Java
* The beginnings of a prolog implementation, never finished
Web
* IRC and HTTP, clients and daemons
* A webcomic site for a friend, until the project was cancelled
* A heirarchical board called "thread"
* My own minimalist website
Low-level
* An operating system based on a programming language interpreter in the kernel (actually partially implemented, including the kernel, filesystem, memory manager, terminal, and the language itself), and tons of other plans for other designs that never were built
* A 16-bit von-neumann stack-based CPU in Minecraft using pure redstone, before the age of comparators, hoppers, and command blocks
* A CPU design for real life on paper, never implemented, and a basic virtual marchine for that CPU
Games
* Tons of games in Scratch from when I was younger, too many to list
* I owned a Minecraft server with 60+ concurrent connections at peak hours for a couple years
- most of the content was based on custom scripts, most of which I wrote-- most vanilla content was replaced somehow, including map generation, monster spawns, the actual monsters themselves, radiation and thirst mechanics, and the beginnings of a technology mod
- I learned through trial-and-error (mostly error) how to manage a large community of people effectively
- this was how I really got into programming
- used a custom modpack, distributed via a self-hosted technic solder instance
- this is how I learnt about VPSes, and was my first introduction to Linux
- included a network of sub-servers (the desert world, the ice world, the normal world, the vanilla desert world, a games server, a sandbox server + quest build server, and a hub) via Bungee-- though this was overkill for the server population so I went back to one server with multiple worlds
* A Minecraft server implementation written in Rust
- built from reverse-engineered protocol docs (http://wiki.vg/Protocol)
- never got enough done to be useable for gameplay, but it was a cool project
* A Minecraft clone written in C# with unity. I wrote the
- infinite map generation with simplex noise that, if I recall correctly, I implemented myself
- mesh generation and optimization
- map editing capabilities
- most of the way to networked multiplayer (partially TCP, partially UDP)
* I've used and written various event systems and can relate them to reactive programming
* Generic simple games like pongs, breakouts, snakes, etc
* I have a pretty solid knowledge of OpenGL, but haven't written anything complex using it directly
Robotics
* A bunch of internal abstractions for our robotics club involving basic functionality like motor controls, input mapping and configuration, and operation modes
* A dataflow abstraction that got sidetracked into a reflection-based implementation of reactive programming for Java and then evolved into another project
* Started work on cube recognition software, but we had a really bad season and dropped out long before it was completed
Current Projects
================
Active
* A programming language derived from dependent ordered linear type theory (and hopefully homotopy theory influences if I ever learn it) based on the construction of valid terms using context-sensitive grammar production rules, with an emphasis on practicality (hey, don't laugh!)
* A rule processing engine + transactional database focused on generating, processing, and querying business data, using modern structure and a powerful rule description language
Planned, eventually
* An operating system based on my programming language and category-theoretic abstractions, rather than the traditional model (I believe this will make things simpler while still being useable, hopefully)
* A distributed overlay network for a secure, autonomous internet, and powerful abstractions for writing internet-based applications and datastores, and decentralized networks
- the two above concepts are extremely closely intertwined with eachother and the language
Real-life stuff
===============
Clubs:
* Robotics (school club)
* Dungeons & dragons (school club)
* Dungeons & dragons (group of friends)
* Speech & debate (dropped out this year, definitely will do next year)
* Marching band (class, during football season)
* Concert band (class, the rest of the year)
* Jazz band (0-period class before school)
Things I like to do:
* Hiking & backpacking
* Cycling (to a lesser degree)
* Dungeons & dragons
* Perform music
* Listen to all sorts of music
* Play board games or poker (for chips) & chat with friends
* Occasional video games like Dwarf Fortress, Factorio, or Terraria with friends, formerly a LOT LOT of Minecraft
Hobbies:
* Programming language theory
* Type theory & other mathematical stuff
* Linguistics & artificial language construction (conlanging)
* Worldbuilding (formerly, and hopefully again someday)
* Music theory (this one is more far off, in that I don't work with it a lot yet)
In summary...
* I am fascinated by conceptual structure & expression (programming languages, human languages, mathematics, music theory, speech & debate)
* I love creativity in structured contexts (worldbuilding, conlanging, dungeons & dragons, music theory)
* I love music (concert band, marching band, jazz band, music theory)
* I love nature

BIN
resume3.docx Normal file

Binary file not shown.

View File

@ -1,59 +0,0 @@
#lang racket
;; /robots.txt specifies how web crawlers should access your website
;; see www.robotstxt.org
; Generate a robots.txt field
(define (robots-field name (body '()))
(define robots-field-base (string-append name ":"))
(if (null? body) robots-field-base
(string-append robots-field-base " " body)))
; Generate a user agent line
(define (robots-ua (name "*"))
(robots-field "User-agent" name))
; Generate a bunch of Disallow lines from a list of urls
(define (robots-disallow list)
(if (empty? list) (robots-field "Disallow")
(string-append*
(map list (lambda (url)
(robots-field "Disallow" url))))))
; Map into and unwrap an optional value: if x present, f x, else d
(define (when-present d f x)
(if (null? x) d
(apply f x)))
; Forbid specific urls to a specific bot by user agent
(define (robots-forbidbot bot disallows)
(string-append
(robots-ua bot)
(robots-disallow disallows)))
; Blocks format: (cons (list of global blocks) (list of (cons bot-ua (list of urls))))
(define (robots-config (blocks '())
#:crawl-delay (crawl-delay 10) ; How frequently a bot should access your site-- poorly specified
#:host (host '()) ; The canonical domain for your website
#:sitemap (sitemap '())) ; Your sitemap.xml
(define (field-when-present name value)
(when-present "" ((curry robots-field) name) value))
(define block-lists
(when-present ""
(match-lambda
([cons global rest]
(string-append
; First we have the global disallow rules
(robots-disallow global)
(string-append*
; then a list of the disallow rules for individual bots
(map (match-lambda
([cons bot urls]
(robots-forbidbot bot urls))) rest)))))
blocks))
(string-append
(robots-ua)
block-lists
(robots-field "Crawl-delay" (number->string crawl-delay))
(field-when-present "Sitemap" sitemap)
(field-when-present "Host" host)))

View File

@ -1,15 +0,0 @@
#lang racket
(require "sitemap.rkt")
(require "robots.rkt")
(define base-url "https://lijero.co")
(define (site-page url body #:priority priority #:lastmod lastmod #:changefreq changefreq)
(cons (sitemap-url (string-append base-url url) #:priority priority #:lastmod lastmod #:changefreq changefreq)
(cons url (xexprs body))))
(define (gen-site pages)
(define sitemap-urls (append* (map (match-lambda ([cons sitemap _] sitemap)) pages)))
(define page-bodies (append* (map (match-lambda ([cons _ page] page)) pages)))
(cons (sitemap sitemap-urls)
(page-bodies)

View File

@ -1,26 +0,0 @@
#lang racket
(require "xexprs/xexprs.rkt")
; A quick sitemap-xml generator (https://www.sitemaps.org/)
; Sitemaps help web crawlers index your website
; Ugly hack because I'm bad at Racket
(define (when-present name value rest)
(if (null? value)
rest
(cons (cons name value) rest)))
; A sitemap URL entry
; https://www.sitemaps.org/protocol.html
(define (sitemap-url loc #:lastmod (lastmod '()) #:changefreq (changefreq '()) #:priority (priority 0.5))
`(url (priority ,priority)
,@(when-present "lastmod" lastmod
(when-present "changefreq" changefreq
'()))))
; Generates a sitemap xml
(define (sitemap urls)
(string-append
"<?xml version="1.0" encoding="UTF-8"?>"
(xexprs
`(urlset #:xmlns "http://www.sitemaps.org/schemas/sitemap/0.9"
,@urls))))

View File

@ -1,73 +0,0 @@
#lang racket/base
(require racket/tcp)
(require racket/string)
; I don't know what the hell is going on but I can't find any useful docs on anything, so... fuck it!
(define (string-empty? str)
(eq? (string-length str) 0))
(define (string-index str c)
(define (string-index-p i)
(if (or (eq? (string-length str) i) (eq? (string-ref str i) c)) i
(string-index-p (+ i 1))))
(string-index-p 0))
(define (string-cut str c)
(define index (string-index str c))
(values (substring str 0 index) (substring str (+ index 1))))
; Fucking hell
(define (string-split str c)
(define-values (head tail) (string-cut str c))
(if (string-empty? tail)
(list head)
(cons (head (string-split tail c)))))
(define (parse-request line)
(string-split line #\ ))
(define (parse-header line)
(define-values (head tail) (string-cut line #\:))
(cons (string->symbol head) tail))
(define (read-headers in)
(define (read-header)
(define line (read-line in))
(if (or (eof-object? line) (string-empty? line)) (list)
(cons (parse-header line) (read-header in))))
(make-immutable-hash (read-header)))
(define (serve handler #:port (port 8080))
(define listener (tcp-listen port 4 #t))
(define (handle in out)
(define request-line (parse-request (read-line in)))
(define request-headers (read-headers in))
(define message-body "") ; Temporary
(display (handler request-line request-headers message-body) out)
(close-input-port in)
(close-output-port out))
(define (loop)
(define-values (in out) (tcp-accept listener))
(thread (λ () (handle in out)))
(loop))
(loop))
(define status/ok '(200 "OK"))
(define (headers->string headers)
(define (header->string header)
(string-append (symbol->string (car header)) ": " (cdr header)))
(string-join (map header->string (hash->list headers)) "\r\n"))
(define (response (body "") #:status (status status/ok) #:headers (headers '()))
(string-append
"HTTP/1.0 " (number->string (car status)) (cadr status) "\r\n"
(headers->string headers) "\r\n\r\n"
body))
(define (my-handler req headers body)
(response "<html><body>test</body></html>" #:headers (make-immutable-hash '(Content-Type "text/html; charset=UTF-8"))))
(serve my-handler)

BIN
scr/leksah0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

142
scr/leksah0.txt Normal file
View File

@ -0,0 +1,142 @@
lijero@desktop:~/build/leksah$ stack exec --no-ghc-package-path leksah
Using default Yi configuration
Linked with -threaded
Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged.
Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged.
Reading keymap from /home/lijero/build/leksah/.stack-work/install/x86_64-linux-nopie/lts-9.9/8.0.2/share/x86_64-linux-ghc-8.0.2/leksah-0.16.3.1/data/keymap.lkshk
Error reading session file /home/lijero/build/leksah/.stack-work/install/x86_64-linux-nopie/lts-9.9/8.0.2/share/x86_64-linux-ghc-8.0.2/leksah-0.16.3.1/data/current.lkshs : Error reading file "/home/lijero/build/leksah/.stack-work/install/x86_64-linux-nopie/lts-9.9/8.0.2/share/x86_64-linux-ghc-8.0.2/leksah-0.16.3.1/data/current.lkshs" "/home/lijero/build/leksah/.stack-work/install/x86_64-linux-nopie/lts-9.9/8.0.2/share/x86_64-linux-ghc-8.0.2/leksah-0.16.3.1/data/current.lkshs" (line 12, column 23):
unexpected read parser no parse Nothing
expecting field parser
CallStack (from HasCallStack):
error, called at src/Text/PrinterParser.hs:284:28 in ltk-0.16.2.0-20pNDZSt43Z2Dmg2j8UhX4:Text.PrinterParser
update workspace info called
Could not retrieve vcs-conf for active package. No vcs-conf set up.
update workspace info called
Now updating system metadata ...
callCollector
setChildren [0,0]
setChildren [1,0]
setChildren [0,0]
setChildren [1,0]
***server start
Bind 127.0.0.1:11111
Metadata collector has nothing to do
Metadata collection has finished
callCollector finished
Finished updating system metadata
Now loading metadata ...
now loading metadata for package Cabal-1.24.2.0
now loading metadata for package Cabal-2.0.1.1
now loading metadata for package array-0.5.1.1
now loading metadata for package base-4.9.1.0
now loading metadata for package binary-0.8.3.0
now loading metadata for package bytestring-0.10.8.1
now loading metadata for package containers-0.5.7.1
now loading metadata for package deepseq-1.4.2.0
now loading metadata for package directory-1.3.0.0
now loading metadata for package filepath-1.4.1.1
now loading metadata for package ghc-8.0.2
now loading metadata for package ghc-boot-8.0.2
now loading metadata for package ghc-boot-th-8.0.2
now loading metadata for package ghc-prim-0.5.0.0
now loading metadata for package ghci-8.0.2
now loading metadata for package haskeline-0.7.3.0
now loading metadata for package hoopl-3.10.2.1
now loading metadata for package hpc-0.6.0.3
now loading metadata for package integer-gmp-1.0.0.1
now loading metadata for package pretty-1.1.3.3
now loading metadata for package process-1.4.3.0
now loading metadata for package rts-1.0
now loading metadata for package template-haskell-2.11.1.0
now loading metadata for package terminfo-0.4.0.2
now loading metadata for package time-1.6.0.1
now loading metadata for package transformers-0.5.2.0
now loading metadata for package unix-2.7.2.1
now loading metadata for package xhtml-3000.2.1
Finished loading metadata
Now updating workspace metadata ...
updatePackageInfo False PackageIdentifier {pkgName = PackageName {unPackageName = "leksah-welcome"}, pkgVersion = Version {versionBranch = [0,16,0,0], versionTags = []}}
updatePackageInfo modToUpdate ["Main (/home/lijero/.leksah-0.16/leksah-welcome/src/Main.hs)","Main (/home/lijero/.leksah-0.16/leksah-welcome/test/Main.hs)"]
callCollectorWorkspace
callCollectorWorkspace finished
Finished updating workspace metadata
setChildren [1,0]
setChildren [1,0,0]
setChildren [1,0]
setChildren [1,0]
setChildren [1,0,2]
setChildren [1,0,2]
setChildren [1,0,2,0]
setChildren [1,0,2]
setChildren [1,0,2,1]
setChildren [1,0,2]
setChildren [1,0,2,2]
setChildren [1,0,2]
setChildren [1,0,2]
setChildren [1,0,2]
setChildren [1,0,2]
setChildren [0,0]
setChildren [0,0,0]
setChildren [0,0]
setChildren [0,0]
setChildren [0,0,2]
setChildren [0,0]
setChildren [0,0,0]
setChildren [0,0]
setChildren [0,0]
setChildren [0,0,2]
setChildren [0,0,2]
setChildren [0,0,2,0]
setChildren [0,0,2]
setChildren [0,0,2,1]
setChildren [0,0,2]
setChildren [0,0,2,2]
setChildren [0,0,2]
setChildren [0,0,2]
setChildren [0,0,2]
setChildren [0,0,2]
setChildren [1,0,2]
setChildren [1,0,2,0]
setChildren [1,0,2]
setChildren [1,0,2,1]
setChildren [1,0,2]
setChildren [1,0,2,2]
setChildren [1,0,2]
setChildren [1,0,2]
setChildren [1,0,2]
setChildren [1,0,2]
setChildren [0,0]
setChildren [0,0,0]
setChildren [0,0]
setChildren [0,0]
setChildren [0,0,2]
setChildren [0,0,2]
setChildren [0,0,2,0]
setChildren [0,0,2]
setChildren [0,0,2,1]
setChildren [0,0,2]
setChildren [0,0,2,2]
setChildren [0,0,2]
setChildren [0,0,2]
setChildren [0,0,2]
setChildren [0,0,2]
setChildren [0,0,2,1]
setChildren [1,0]
setChildren [1,0,0]
setChildren [1,0]
setChildren [1,0]
setChildren [1,0,2]
setChildren [1,0,2]
setChildren [1,0,2,0]
setChildren [1,0,2]
setChildren [1,0,2,1]
setChildren [1,0,2]
setChildren [1,0,2,2]
setChildren [1,0,2]
setChildren [1,0,2]
setChildren [1,0,2]
setChildren [1,0,2]
setChildren [1,0,2,1]
^C***lost connection
***lost last connection - exiting
^C

BIN
scr/leksah1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

5536
scr/leksah1.txt Normal file

File diff suppressed because it is too large Load Diff

BIN
scr/leksah2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
scr/leksah3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

85
scr/leksah3.txt Normal file
View File

@ -0,0 +1,85 @@
Using default Yi configuration
Linked with -threaded
Reading keymap from /home/lijero/build/leksah/.stack-work/install/x86_64-linux-nopie/lts-9.9/8.0.2/share/x86_64-linux-ghc-8.0.2/leksah-0.16.3.1/data/keymap.lkshk
Now updating system metadata ...
callCollector
***server start
Bind 127.0.0.1:11111
Metadata collector has nothing to do
Metadata collection has finished
callCollector finished
Finished updating system metadata
Now loading metadata ...
now loading metadata for package Cabal-1.24.2.0
now loading metadata for package X11-1.8
now loading metadata for package X11-xft-0.3.1
now loading metadata for package array-0.5.1.1
now loading metadata for package base-4.9.1.0
now loading metadata for package binary-0.8.3.0
now loading metadata for package bytestring-0.10.8.1
now loading metadata for package containers-0.5.7.1
now loading metadata for package data-default-0.7.1.1
now loading metadata for package data-default-class-0.1.2.0
now loading metadata for package data-default-instances-containers-0.0.1
now loading metadata for package data-default-instances-dlist-0.0.1
now loading metadata for package data-default-instances-old-locale-0.0.1
now loading metadata for package deepseq-1.4.2.0
now loading metadata for package directory-1.3.0.0
now loading metadata for package dlist-0.8.0.3
now loading metadata for package extensible-exceptions-0.1.1.4
now loading metadata for package filepath-1.4.1.1
now loading metadata for package ghc-8.0.2
now loading metadata for package ghc-boot-8.0.2
now loading metadata for package ghc-boot-th-8.0.2
now loading metadata for package ghc-prim-0.5.0.0
now loading metadata for package ghci-8.0.2
now loading metadata for package haskeline-0.7.3.0
now loading metadata for package hoopl-3.10.2.1
now loading metadata for package hpc-0.6.0.3
now loading metadata for package integer-gmp-1.0.0.1
now loading metadata for package mtl-2.2.1
now loading metadata for package old-locale-1.0.0.7
now loading metadata for package old-time-1.1.0.3
now loading metadata for package pretty-1.1.3.3
now loading metadata for package process-1.4.3.0
now loading metadata for package random-1.1
now loading metadata for package rts-1.0
now loading metadata for package setlocale-1.0.0.5
now loading metadata for package template-haskell-2.11.1.0
now loading metadata for package terminfo-0.4.0.2
now loading metadata for package time-1.6.0.1
now loading metadata for package transformers-0.5.2.0
now loading metadata for package unix-2.7.2.1
now loading metadata for package utf8-string-1.0.1.1
now loading metadata for package xhtml-3000.2.1
now loading metadata for package xmonad-0.13
now loading metadata for package xmonad-contrib-0.13
Finished loading metadata
updateWorkspaceInfo' no workspace
Now updating workspace metadata ...
update workspace info called
Could not retrieve vcs-conf for active package. No vcs-conf set up.
setChildren [0,0]
Now updating workspace metadata ...
updatePackageInfo False PackageIdentifier {pkgName = PackageName {unPackageName = "test-leksah"}, pkgVersion = Version {versionBranch = [0,0,1], versionTags = []}}
updatePackageInfo modToUpdate []
callCollectorWorkspace
callCollectorWorkspace: Nothing to do
Finished updating workspace metadata
update workspace info called
setChildren [0,0]
setChildren [0,0,0]
setChildren [0,0]
setChildren [0,0]
setChildren [0,0,2]
setChildren [0,0,2]
setChildren [0,0,2]
setChildren [0,0]
Now updating workspace metadata ...
updatePackageInfo False PackageIdentifier {pkgName = PackageName {unPackageName = "test-leksah"}, pkgVersion = Version {versionBranch = [0,0,1], versionTags = []}}
updatePackageInfo modToUpdate []
callCollectorWorkspace
callCollectorWorkspace: Nothing to do
Finished updating workspace metadata
***lost connection
***lost last connection - exiting

BIN
scr/leksaha0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
scr/leksaha1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -6,4 +6,10 @@
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://lijero.co/articles/beyond-operating-systems</loc>
<lastmod>2017-10-07</lastmod>
<changefreq>daily</changefreq>
<priority>0.7</priority>
</url>
</urlset>

296
switteprim.txt Normal file
View File

@ -0,0 +1,296 @@
INTRODUCTION
=================
This system is derived from linear type theory, such that for a value x with type A:
(x : A) means that x must be used exactly once.
(x : ?A) means that x may be used at most once, or forgotten.
(x : !A) means that x may be used multiple times, but at least once.
(x : ?!A) means that x may be used zero or more times.
? is read "why not", and ! is read "of course".
Additive means "there are two possibilities, but you only get one". In other words,
in each branch of an additive relationship, all of the non-? variables in the
context must be disposed of.
Multiplicative means "you get both of these at once". In other words, all of the
non-? variables must be disposed of as a whole.
Conjunction means "both values exist at once".
Disjunction means "only one of these values exist at once".
Additive conjunction (a & b) means "you can use either a or b, it's up to you which".
Additive disjunction (a + b) means "I am going to give you an a or a b, and you must
be prepared to deal with either, but not both at the same time."
Multiplicative conjunction (a * b) means "I am going to give you an a and a b, and
you have to use both".
Multiplicative disjunction (a | b) means "you must be prepared to recieve both an a
and a b, but ultimately only one will be used". If that's a bit confusing, that's alright.
AXIOM
=====
a | -a
where -a represents the dual of a, and | represents multiplicative disjunction.
This is the axiom of the excluded middle, meaning to "a is true or not true".
Its implementation is explained in "multiplicative disjunction". There are no
further axioms.
Duals:
While they're a general construct, the dual is actually only used for the
definition of the axiom, so I'll specify it here:
-(-a) = a
-(a & b) = -a + -b
-(a * b) = -a | -b
-Top = 0
-1 = Bottom
-(!a) = ?(-a)
and vice versa in all cases.
Distributivity:
This isn't actually related to the axiom, but I might as well while I'm at it.
None of these are built-in rules, they are just helpful notions provable within
the language itself. These are the distributive laws:
a * (b + c) = (a * b) + (a * c)
a | (b & c) = (a | b) & (a | c)
a * 0 = 0
a & Top = Top
notice how "exponentials" convert "addition" into "multiplication"-- hence the names:
!(a & b) = !a * !b
?(a + b) = ?a | ?b
!Top = 1
?0 = Bottom
and vice versa in all cases in both sets listed.
STRUCTURAL RULES
================
The weakening and contraction rules are specified twice since
I hope to extend this into an ordered logic, so I have to include
the exchange-requiring equivalents. This is also true for constructors and
eliminators in the computational rules. All of these can be implemented only
once, with the second rule being implemented in terms of the first via a swap
that /doesn't/ apply an unordered constraint. If I do not extend this to an
ordered logic, you can simply ignore all of the second rules.
Weakening: a -> ?b -> a ### const
?a -> b -> b ### flip const
Contraction: (a -> !a -> b) -> (!a -> b) ### join
(!a -> a -> b) -> (!a -> b) ### join . flip
Exchange: (a -> b -> c) -> (b -> a -> c) ### flip
(or equivalently (a * b) -> (b * a))
(todo: do I need a dual exchange rule for &?)
COMPUTATIONAL RULES
===================
These are the introduction and elimination rules for compound terms in the
language. Introduction terms are labeled with an i, elimination terms with an e.
When multiple introduction/elimination rules are required, they are each labelled
with a number.
Additive conjunction (with):
Topi1 : a -> a & Top
Topi2 : a -> Top & a
additively (all of the context is used in either branch of the options a and b),
&i : a -> b -> a & b
&e1 : a & b -> a
&e2 : a & b -> b
The eliminators may be called "projections".
There is no elimination rule for Top, since it doesn't exist. It can only
be introducted in terms of the type signatures in Top1 and Top2, and the
only thing you can do with it is ignore it via the associated projection.
It doesn't have to exist because nothing using the projection for Top
can exist because it cannot be used for anything, nor weakened.
Additive conjunction can be interpreted as a pair of procedure pointers,
with the context enclosed inside. The projections are function calls that
choose which procedure to invoke to consume the context. A call to Top
is equivalent to nontermination, since Top doesn't exist.
The compiler could probably safely maybe automatically insert the
eliminators when the corresponding type is required, but I haven't totally
thought this through, and there are potential issues with e.g.
(a & b) & a, in the event that choice of a matters.
Additive disjunction (plus):
0e : 0 -> a
+i1 : a -> a + b
+i2 : b -> a + b
+e1 : (a -> c) & (b -> c) -> (a + b -> c)
+e2 : (b -> c) & (a -> c) -> (a + b -> c)
0, like Top, does not exist. It only exists as a fragment of the type
signature in disjunction introduction, because
+i1 (x : A) : forall b. A + b
and 0 is simply an instanciation of b, taking the entire forall thing
far too literally, as shown in its eliminator. It is impossible to
have an actual instance of 0, because by definition, it is the type
not selected when you create a +. In terms of elimination, all eliminations
of an 0 + a type are equivalent to (e1 0e), with the exception of the fact
that you have to destroy anything in your context that cannot be weakened.
This can be trivially implemented as using 0e to generate a function type
that directly consumes all of the terms in the context, and returning a c.
The eliminators are rather intuitive. The choice of & is necessary because
each option must entirely dispose of its context, as is in the definition
of &i.
A value of a + b is trivial: it's just a tagged union, i.e. an indicator
of whether it's a or b, and the value a or b.
Multiplicative conjunction (times):
1i : 1
1e1 : 1 * a -> a
1e2 : a * a -> a
*i : a -> b -> a * b
*e1 : a * b -> (a -> b -> c) -> c
*e2 : (a -> b -> c) -> a * b -> c
1 does exist, and in fact its sole introduction rule is "1 exists", but
it holds no information, so in practice it doesn't have to be stored.
Formally it has only one elimination rule, 1 -> <nothing>, but a function
can't return nothing, so instead you have to eliminate it via its definition
as the identity element.
The rest of it is pretty intuitive. In memory, it's just a pair of values.
Multiplicative disjunction (par):
Bottomi1 : a -> a | Bottom
Bottomi2 : a -> Bottom | a
Bottome : Bottom -> a
|i : ?a * ?b -> a | b
|e1 : ?(a -> c) * ?(b -> c) -> a | b -> c
|e2 : a | b -> ?(a -> c) * ?(b -> c) -> c
Multiplicative disjunction is by far the least intuitive operator, corresponding
to delimited continuations and functions.
Bottom does not exist. Like with additive disjunction, it's just part of
the type signature, and it simply exists to not get chosen.
As you can see, |e produces only one c despite having two options, both
of which are provided in |i. That's because |e is inherently
nondeterministic. |i and |e are both entirely weakened because neither
choice will necessarily be chosen, yet they both must exist in full. This means
the entire closure that they are in must be somehow weakened, since it's
not possible to dispose of a full value in both branches at once, because
that would constitute double use. The use of the * in the signature is to
emphasize the relationship to multiplicative conjunction and that behavior,
just as additive disjunction is defined in terms of additive conjunction.
A par value is implemented in terms of a pair of function calls. In the
eliminator, either function may be invoked, and when the value is used,
the eliminator may choose to forget the function halfway through and jump
to the other option instead, making it equivalent to a continuation, the
functional equivalent to a goto.
The main use of par is in the sole axiom of the excluded middle, which encodes
the equivalent to functions and delimited continuations. For reference, the type
of a function is defined as (a -> b = -a | b). Essentially, the axiom can't pull
a value of type A out of thin air, so it is forced to choose the -a branch.
-a is equivalent to a -> Bottom, and therefore can only be used by providing a
value of type a, so instead of actually providing that Bottom, the function
simply jumps to the branch that demanded an a in the first place and returns
that result. Functions are implemented the same way, only kinda in reverse:
it runs the side that claims to have an extra a it needs to dispose of, and then
once it gets that hole, it produces the a in the other branch and terminates.
Implicitly in either case the context is consumed, which is equivalent to the
function returning. As you can see though, these are simply different
perspectives on the same axiom.
If you don't get it, that's fine, because it's super confusing, and I don't
understand it either.
TYPECLASSES & MODULES
=====================
I haven't really figured out typeclasses. Basically I intend for them to be
existential types (via dependent sums maybe?), but I need to figure out how to
make it practical first.
Requirements:
* It must be possible to use the instanced values without having to unwrap the
class implementation manually first.
* It must be possible to use the function instances equally easily, and without
having to declare the names at each usage point.
* They must permit non-unique instances.
* Instances must be stackable, the outermost one being used unless the inner one
is exposed within one of the instance type-contextual manipulations (e.g. functor).
This is important especially since Copy should implement !, but it should be
possible to rc a copiable variable and have it behave as expected. Copy is
described in more detail in Mutation.
Modules are essentially the same thing as typeclasses, and have similar
requirements. The answer to both probably lies in the same place. Lightweight
modules that are as easy to use as typeclasses would be a major plus too.
I don't suspect this problem will be all that hard to resolve.
As far as ! and ? go, they are essentially typeclasses. @ below is a typeclass
too. Essentially, these are the introduction rules for ! and ?, though these
are not possible to derive without external functions (for obvious reasons),
and being typeclasses, it's not appropriate to give them introduction rules.
To specify a !, you need a class instance satisfying either the contraction rule,
or equivalently, the following:
!i : a -> !(() -> a)
To specify a ?, you need a class instance satisfying either the weakening rule,
or equivalently, the following:
?i : a -> ?(a -> ())
The reason these are essentially introduction rules is made more obvious if you
wrap the entire thing into a (-> !a) or (-> ?a) respectively.
MUTATION
========
@ means "mutable" to the compiler. Normal values are immutable, which means to
make changes, the entire object has to be deconstructed and reconstructed again.
Mutation allows direct modification to the data structure without concern.
Generally things are mutable by default, but this may not be the case with
external values, or internal values via pointers.
@ extends ?, which means a mutable pointer may be freed, but not !, so that
you cannot have multiple instances of a mutable pointer.
Losing mutation in favor of replication:
rc : @a -> !?a, introducing a reference-counted pointer
Some values may implement Copy, allowing deep duplication. All composite
structures may automatically derive Copy whenever both of their constituents
are !. Copy, of course, is an implementation of !, though using (rc) anyway
may be desirable for performance reasons, especially for highly composite
structures.
copy : Copy a => a -> @a
Generally, syntactic sugar should eliminate most of this crap such that the
programmer shouldn't have to deal with it most of the time.

65
template.xhtml Executable file
View File

@ -0,0 +1,65 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<!-- Uses Open Iconic: MIT licenses, attribution optional licenses. -->
<!-- This page is friendly to text browsers. -->
<head>
<meta charset="utf-8" />
<meta name="author" content="Lijero" />
<!-- <meta name="description" content="" /> -->
<meta name="keywords" content="Lijero,music,code,producer,games,website" />
<meta name="robots" content="index,follow" />
<title>Lijero</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="/favicon.png" rel="icon" type="image/png" />
<link href="/res/common.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
var _paq = _paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
_paq.push(["setCookieDomain", "*.lijero.co"]);
_paq.push(["setDomains", ["*.lijero.co"]]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//p.lijero.co/";
_paq.push(['setTrackerUrl', u+'foo']);
_paq.push(['setSiteId', '1']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'foo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
</head>
<body>
<nav>
<div id="navbrand">Lijero</div>
<ul>
<li><a href="/">Home</a></li>
<li>Music</li>
<li>Games</li>
<li>About</li>
</ul>
</nav>
<article>
<header>
<h1>Test Content</h1>
</header>
</article>
<footer>
<div class="metadata">
<span><img alt="Author" src="//lijero.co/res/icon/person.svg" /> Lijero</span>
<span><img alt="Updated" src="//lijero.co/res/icon/clock.svg" /> 2017-12-16</span>
<div class="license">
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">
<img alt="This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License" style="border-width:0" src="/res/cc-by-sa-small.png" />
</a>
</div>
</div>
</footer>
</body>
</html>

1
xexprs

@ -1 +0,0 @@
Subproject commit 2026c23aa83b6dd7f9bb03e38185a850ec6a2aac