--- /dev/null
+.bundle
+.idea
+.jekyll-cache
+.jekyll-metadata
+.sass-cache
+.source
+_site
+vendor
+
--- /dev/null
+---
+permalink: /404.html
+layout: default
+styles: assets/index.css
+---
+
+<style type="text/css" media="screen">
+ .container {
+ margin: 10px auto;
+ max-width: 600px;
+ text-align: center;
+ }
+ h1 {
+ margin: 30px 0;
+ font-size: 4em;
+ line-height: 1;
+ letter-spacing: -1px;
+ }
+ html {
+ height: 100%;
+ }
+ body.default {
+ display: flex;
+ align-items: center;
+ margin: 0;
+ height: 100%;
+ }
+</style>
+
+<div class="container">
+ <h1>404</h1>
+
+ <p><strong>Page not found :(</strong></p>
+ <p>The requested page could not be found.</p>
+</div>
--- /dev/null
+source "https://rubygems.org"
+
+# gem "jekyll", "~> 4.2"
+# gem "github-pages"
+gem "github-pages", "~> 219", group: :jekyll_plugins
+
+group :jekyll_plugins do
+ gem "jekyll-feed"
+ gem "jekyll-sitemap"
+ gem "jekyll-relative-links"
+end
--- /dev/null
+GEM
+ remote: https://rubygems.org/
+ specs:
+ activesupport (6.0.4.1)
+ concurrent-ruby (~> 1.0, >= 1.0.2)
+ i18n (>= 0.7, < 2)
+ minitest (~> 5.1)
+ tzinfo (~> 1.1)
+ zeitwerk (~> 2.2, >= 2.2.2)
+ addressable (2.8.0)
+ public_suffix (>= 2.0.2, < 5.0)
+ coffee-script (2.4.1)
+ coffee-script-source
+ execjs
+ coffee-script-source (1.11.1)
+ colorator (1.1.0)
+ commonmarker (0.17.13)
+ ruby-enum (~> 0.5)
+ concurrent-ruby (1.1.9)
+ dnsruby (1.61.7)
+ simpleidn (~> 0.1)
+ em-websocket (0.5.2)
+ eventmachine (>= 0.12.9)
+ http_parser.rb (~> 0.6.0)
+ ethon (0.15.0)
+ ffi (>= 1.15.0)
+ eventmachine (1.2.7)
+ execjs (2.8.1)
+ faraday (1.8.0)
+ faraday-em_http (~> 1.0)
+ faraday-em_synchrony (~> 1.0)
+ faraday-excon (~> 1.1)
+ faraday-httpclient (~> 1.0.1)
+ faraday-net_http (~> 1.0)
+ faraday-net_http_persistent (~> 1.1)
+ faraday-patron (~> 1.0)
+ faraday-rack (~> 1.0)
+ multipart-post (>= 1.2, < 3)
+ ruby2_keywords (>= 0.0.4)
+ faraday-em_http (1.0.0)
+ faraday-em_synchrony (1.0.0)
+ faraday-excon (1.1.0)
+ faraday-httpclient (1.0.1)
+ faraday-net_http (1.0.1)
+ faraday-net_http_persistent (1.2.0)
+ faraday-patron (1.0.0)
+ faraday-rack (1.0.0)
+ ffi (1.15.4)
+ forwardable-extended (2.6.0)
+ gemoji (3.0.1)
+ github-pages (219)
+ github-pages-health-check (= 1.17.7)
+ jekyll (= 3.9.0)
+ jekyll-avatar (= 0.7.0)
+ jekyll-coffeescript (= 1.1.1)
+ jekyll-commonmark-ghpages (= 0.1.6)
+ jekyll-default-layout (= 0.1.4)
+ jekyll-feed (= 0.15.1)
+ jekyll-gist (= 1.5.0)
+ jekyll-github-metadata (= 2.13.0)
+ jekyll-mentions (= 1.6.0)
+ jekyll-optional-front-matter (= 0.3.2)
+ jekyll-paginate (= 1.1.0)
+ jekyll-readme-index (= 0.3.0)
+ jekyll-redirect-from (= 0.16.0)
+ jekyll-relative-links (= 0.6.1)
+ jekyll-remote-theme (= 0.4.3)
+ jekyll-sass-converter (= 1.5.2)
+ jekyll-seo-tag (= 2.7.1)
+ jekyll-sitemap (= 1.4.0)
+ jekyll-swiss (= 1.0.0)
+ jekyll-theme-architect (= 0.2.0)
+ jekyll-theme-cayman (= 0.2.0)
+ jekyll-theme-dinky (= 0.2.0)
+ jekyll-theme-hacker (= 0.2.0)
+ jekyll-theme-leap-day (= 0.2.0)
+ jekyll-theme-merlot (= 0.2.0)
+ jekyll-theme-midnight (= 0.2.0)
+ jekyll-theme-minimal (= 0.2.0)
+ jekyll-theme-modernist (= 0.2.0)
+ jekyll-theme-primer (= 0.6.0)
+ jekyll-theme-slate (= 0.2.0)
+ jekyll-theme-tactile (= 0.2.0)
+ jekyll-theme-time-machine (= 0.2.0)
+ jekyll-titles-from-headings (= 0.5.3)
+ jemoji (= 0.12.0)
+ kramdown (= 2.3.1)
+ kramdown-parser-gfm (= 1.1.0)
+ liquid (= 4.0.3)
+ mercenary (~> 0.3)
+ minima (= 2.5.1)
+ nokogiri (>= 1.10.4, < 2.0)
+ rouge (= 3.26.0)
+ terminal-table (~> 1.4)
+ github-pages-health-check (1.17.7)
+ addressable (~> 2.3)
+ dnsruby (~> 1.60)
+ octokit (~> 4.0)
+ public_suffix (>= 3.0, < 5.0)
+ typhoeus (~> 1.3)
+ html-pipeline (2.14.0)
+ activesupport (>= 2)
+ nokogiri (>= 1.4)
+ http_parser.rb (0.6.0)
+ i18n (0.9.5)
+ concurrent-ruby (~> 1.0)
+ jekyll (3.9.0)
+ addressable (~> 2.4)
+ colorator (~> 1.0)
+ em-websocket (~> 0.5)
+ i18n (~> 0.7)
+ jekyll-sass-converter (~> 1.0)
+ jekyll-watch (~> 2.0)
+ kramdown (>= 1.17, < 3)
+ liquid (~> 4.0)
+ mercenary (~> 0.3.3)
+ pathutil (~> 0.9)
+ rouge (>= 1.7, < 4)
+ safe_yaml (~> 1.0)
+ jekyll-avatar (0.7.0)
+ jekyll (>= 3.0, < 5.0)
+ jekyll-coffeescript (1.1.1)
+ coffee-script (~> 2.2)
+ coffee-script-source (~> 1.11.1)
+ jekyll-commonmark (1.3.1)
+ commonmarker (~> 0.14)
+ jekyll (>= 3.7, < 5.0)
+ jekyll-commonmark-ghpages (0.1.6)
+ commonmarker (~> 0.17.6)
+ jekyll-commonmark (~> 1.2)
+ rouge (>= 2.0, < 4.0)
+ jekyll-default-layout (0.1.4)
+ jekyll (~> 3.0)
+ jekyll-feed (0.15.1)
+ jekyll (>= 3.7, < 5.0)
+ jekyll-gist (1.5.0)
+ octokit (~> 4.2)
+ jekyll-github-metadata (2.13.0)
+ jekyll (>= 3.4, < 5.0)
+ octokit (~> 4.0, != 4.4.0)
+ jekyll-mentions (1.6.0)
+ html-pipeline (~> 2.3)
+ jekyll (>= 3.7, < 5.0)
+ jekyll-optional-front-matter (0.3.2)
+ jekyll (>= 3.0, < 5.0)
+ jekyll-paginate (1.1.0)
+ jekyll-readme-index (0.3.0)
+ jekyll (>= 3.0, < 5.0)
+ jekyll-redirect-from (0.16.0)
+ jekyll (>= 3.3, < 5.0)
+ jekyll-relative-links (0.6.1)
+ jekyll (>= 3.3, < 5.0)
+ jekyll-remote-theme (0.4.3)
+ addressable (~> 2.0)
+ jekyll (>= 3.5, < 5.0)
+ jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0)
+ rubyzip (>= 1.3.0, < 3.0)
+ jekyll-sass-converter (1.5.2)
+ sass (~> 3.4)
+ jekyll-seo-tag (2.7.1)
+ jekyll (>= 3.8, < 5.0)
+ jekyll-sitemap (1.4.0)
+ jekyll (>= 3.7, < 5.0)
+ jekyll-swiss (1.0.0)
+ jekyll-theme-architect (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-cayman (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-dinky (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-hacker (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-leap-day (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-merlot (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-midnight (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-minimal (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-modernist (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-primer (0.6.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-github-metadata (~> 2.9)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-slate (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-tactile (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-theme-time-machine (0.2.0)
+ jekyll (> 3.5, < 5.0)
+ jekyll-seo-tag (~> 2.0)
+ jekyll-titles-from-headings (0.5.3)
+ jekyll (>= 3.3, < 5.0)
+ jekyll-watch (2.2.1)
+ listen (~> 3.0)
+ jemoji (0.12.0)
+ gemoji (~> 3.0)
+ html-pipeline (~> 2.2)
+ jekyll (>= 3.0, < 5.0)
+ kramdown (2.3.1)
+ rexml
+ kramdown-parser-gfm (1.1.0)
+ kramdown (~> 2.0)
+ liquid (4.0.3)
+ listen (3.7.0)
+ rb-fsevent (~> 0.10, >= 0.10.3)
+ rb-inotify (~> 0.9, >= 0.9.10)
+ mercenary (0.3.6)
+ mini_portile2 (2.6.1)
+ minima (2.5.1)
+ jekyll (>= 3.5, < 5.0)
+ jekyll-feed (~> 0.9)
+ jekyll-seo-tag (~> 2.1)
+ minitest (5.14.4)
+ multipart-post (2.1.1)
+ nokogiri (1.12.5)
+ mini_portile2 (~> 2.6.1)
+ racc (~> 1.4)
+ nokogiri (1.12.5-x86_64-linux)
+ racc (~> 1.4)
+ octokit (4.21.0)
+ faraday (>= 0.9)
+ sawyer (~> 0.8.0, >= 0.5.3)
+ pathutil (0.16.2)
+ forwardable-extended (~> 2.6)
+ public_suffix (4.0.6)
+ racc (1.6.0)
+ rb-fsevent (0.11.0)
+ rb-inotify (0.10.1)
+ ffi (~> 1.0)
+ rexml (3.2.5)
+ rouge (3.26.0)
+ ruby-enum (0.9.0)
+ i18n
+ ruby2_keywords (0.0.5)
+ rubyzip (2.3.2)
+ safe_yaml (1.0.5)
+ sass (3.7.4)
+ sass-listen (~> 4.0.0)
+ sass-listen (4.0.0)
+ rb-fsevent (~> 0.9, >= 0.9.4)
+ rb-inotify (~> 0.9, >= 0.9.7)
+ sawyer (0.8.2)
+ addressable (>= 2.3.5)
+ faraday (> 0.8, < 2.0)
+ simpleidn (0.2.1)
+ unf (~> 0.1.4)
+ terminal-table (1.8.0)
+ unicode-display_width (~> 1.1, >= 1.1.1)
+ thread_safe (0.3.6)
+ typhoeus (1.4.0)
+ ethon (>= 0.9.0)
+ tzinfo (1.2.9)
+ thread_safe (~> 0.1)
+ unf (0.1.4)
+ unf_ext
+ unf_ext (0.0.8)
+ unicode-display_width (1.8.0)
+ zeitwerk (2.5.1)
+
+PLATFORMS
+ ruby
+ x86_64-linux
+
+DEPENDENCIES
+ github-pages (~> 219)
+ jekyll-feed
+ jekyll-relative-links
+ jekyll-sitemap
+
+BUNDLED WITH
+ 2.2.30
--- /dev/null
+Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
+
+Creative Commons Corporation (“Creative Commons”) is not a law firm and
+does not provide legal services or legal advice. Distribution of Creative
+Commons public licenses does not create a lawyer-client or other
+relationship. Creative Commons makes its licenses and related information
+available on an “as-is” basis. Creative Commons gives no warranties
+regarding its licenses, any material licensed under their terms and
+conditions, or any related information. Creative Commons disclaims all
+liability for damages resulting from their use to the fullest extent
+possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share original
+works of authorship and other material subject to copyright and certain
+other rights specified in the public license below. The following
+considerations are for informational purposes only, are not exhaustive, and
+do not form part of our licenses.
+
+Considerations for licensors: Our public licenses are intended for use by
+those authorized to give the public permission to use material in ways
+otherwise restricted by copyright and certain other rights. Our licenses
+are irrevocable. Licensors should read and understand the terms and
+conditions of the license they choose before applying it. Licensors should
+also secure all rights necessary before applying our licenses so that the
+public can reuse the material as expected. Licensors should clearly mark
+any material not subject to the license. This includes other CC-licensed
+material, or material used under an exception or limitation to copyright.
+More considerations for licensors.
+
+Considerations for the public: By using one of our public licenses, a
+licensor grants the public permission to use the licensed material under
+specified terms and conditions. If the licensor’s permission is not
+necessary for any reason–for example, because of any applicable exception
+or limitation to copyright–then that use is not regulated by the license.
+Our licenses grant only permissions under copyright and certain other
+rights that a licensor has authority to grant. Use of the licensed material
+may still be restricted for other reasons, including because others have
+copyright or other rights in the material. A licensor may make special
+requests, such as asking that all changes be marked or described. Although
+not required by our licenses, you are encouraged to respect those requests
+where reasonable. More considerations for the public.
+Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
+Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree to
+be bound by the terms and conditions of this Creative Commons
+Attribution-NonCommercial-ShareAlike 4.0 International Public License
+("Public License"). To the extent this Public License may be interpreted as
+a contract, You are granted the Licensed Rights in consideration of Your
+acceptance of these terms and conditions, and the Licensor grants You such
+rights in consideration of benefits the Licensor receives from making the
+Licensed Material available under these terms and conditions.
+
+Section 1 – Definitions.
+
+ a. Adapted Material means material subject to Copyright and Similar
+ Rights that is derived from or based upon the Licensed Material and in
+ which the Licensed Material is translated, altered, arranged, transformed,
+ or otherwise modified in a manner requiring permission under the Copyright
+ and Similar Rights held by the Licensor. For purposes of this Public
+ License, where the Licensed Material is a musical work, performance, or
+ sound recording, Adapted Material is always produced where the Licensed
+ Material is synched in timed relation with a moving image.
+
+ b. Adapter's License means the license You apply to Your Copyright and
+ Similar Rights in Your contributions to Adapted Material in accordance with
+ the terms and conditions of this Public License.
+
+ c. BY-NC-SA Compatible License means a license listed at
+ creativecommons.org/compatiblelicenses, approved by Creative Commons as
+ essentially the equivalent of this Public License.
+
+ d. Copyright and Similar Rights means copyright and/or similar rights
+ closely related to copyright including, without limitation, performance,
+ broadcast, sound recording, and Sui Generis Database Rights, without regard
+ to how the rights are labeled or categorized. For purposes of this Public
+ License, the rights specified in Section 2(b)(1)-(2) are not Copyright and
+ Similar Rights.
+
+ e. Effective Technological Measures means those measures that, in the
+ absence of proper authority, may not be circumvented under laws fulfilling
+ obligations under Article 11 of the WIPO Copyright Treaty adopted on
+ December 20, 1996, and/or similar international agreements.
+
+ f. Exceptions and Limitations means fair use, fair dealing, and/or any
+ other exception or limitation to Copyright and Similar Rights that applies
+ to Your use of the Licensed Material.
+
+ g. License Elements means the license attributes listed in the name of
+ a Creative Commons Public License. The License Elements of this Public
+ License are Attribution, NonCommercial, and ShareAlike.
+
+ h. Licensed Material means the artistic or literary work, database, or
+ other material to which the Licensor applied this Public License.
+
+ i. Licensed Rights means the rights granted to You subject to the
+ terms and conditions of this Public License, which are limited to all
+ Copyright and Similar Rights that apply to Your use of the Licensed
+ Material and that the Licensor has authority to license.
+
+ j. Licensor means the individual(s) or entity(ies) granting rights
+ under this Public License.
+
+ k. NonCommercial means not primarily intended for or directed towards
+ commercial advantage or monetary compensation. For purposes of this Public
+ License, the exchange of the Licensed Material for other material subject
+ to Copyright and Similar Rights by digital file-sharing or similar means is
+ NonCommercial provided there is no payment of monetary compensation in
+ connection with the exchange.
+
+ l. Share means to provide material to the public by any means or
+ process that requires permission under the Licensed Rights, such as
+ reproduction, public display, public performance, distribution,
+ dissemination, communication, or importation, and to make material
+ available to the public including in ways that members of the public may
+ access the material from a place and at a time individually chosen by
+ them.
+
+ m. Sui Generis Database Rights means rights other than copyright
+ resulting from Directive 96/9/EC of the European Parliament and of the
+ Council of 11 March 1996 on the legal protection of databases, as amended
+ and/or succeeded, as well as other essentially equivalent rights anywhere
+ in the world.
+
+ n. You means the individual or entity exercising the Licensed Rights
+ under this Public License. Your has a corresponding meaning.
+
+Section 2 – Scope.
+
+ a. License grant.
+
+ 1. Subject to the terms and conditions of this Public License,
+ the Licensor hereby grants You a worldwide, royalty-free,
+ non-sublicensable, non-exclusive, irrevocable license to exercise the
+ Licensed Rights in the Licensed Material to:
+
+ A. reproduce and Share the Licensed Material, in whole or in
+ part, for NonCommercial purposes only; and
+
+ B. produce, reproduce, and Share Adapted Material for
+ NonCommercial purposes only.
+
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
+ Exceptions and Limitations apply to Your use, this Public License does not
+ apply, and You do not need to comply with its terms and conditions.
+
+ 3. Term. The term of this Public License is specified in Section
+ 6(a).
+
+ 4. Media and formats; technical modifications allowed. The
+ Licensor authorizes You to exercise the Licensed Rights in all media and
+ formats whether now known or hereafter created, and to make technical
+ modifications necessary to do so. The Licensor waives and/or agrees not to
+ assert any right or authority to forbid You from making technical
+ modifications necessary to exercise the Licensed Rights, including
+ technical modifications necessary to circumvent Effective Technological
+ Measures. For purposes of this Public License, simply making modifications
+ authorized by this Section 2(a)(4) never produces Adapted Material.
+
+ 5. Downstream recipients.
+
+ A. Offer from the Licensor – Licensed Material. Every
+ recipient of the Licensed Material automatically receives an offer from the
+ Licensor to exercise the Licensed Rights under the terms and conditions of
+ this Public License.
+
+ B. Additional offer from the Licensor – Adapted Material.
+ Every recipient of Adapted Material from You automatically receives an
+ offer from the Licensor to exercise the Licensed Rights in the Adapted
+ Material under the conditions of the Adapter’s License You apply.
+
+ C. No downstream restrictions. You may not offer or impose
+ any additional or different terms or conditions on, or apply any Effective
+ Technological Measures to, the Licensed Material if doing so restricts
+ exercise of the Licensed Rights by any recipient of the Licensed Material.
+
+ 6. No endorsement. Nothing in this Public License constitutes or
+ may be construed as permission to assert or imply that You are, or that
+ Your use of the Licensed Material is, connected with, or sponsored,
+ endorsed, or granted official status by, the Licensor or others designated
+ to receive attribution as provided in Section 3(a)(1)(A)(i).
+
+ b. Other rights.
+
+ 1. Moral rights, such as the right of integrity, are not licensed
+ under this Public License, nor are publicity, privacy, and/or other similar
+ personality rights; however, to the extent possible, the Licensor waives
+ and/or agrees not to assert any such rights held by the Licensor to the
+ limited extent necessary to allow You to exercise the Licensed Rights, but
+ not otherwise.
+
+ 2. Patent and trademark rights are not licensed under this Public
+ License.
+
+ 3. To the extent possible, the Licensor waives any right to
+ collect royalties from You for the exercise of the Licensed Rights, whether
+ directly or through a collecting society under any voluntary or waivable
+ statutory or compulsory licensing scheme. In all other cases the Licensor
+ expressly reserves any right to collect such royalties, including when the
+ Licensed Material is used other than for NonCommercial purposes.
+
+Section 3 – License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+ a. Attribution.
+
+ 1. If You Share the Licensed Material (including in modified
+ form), You must:
+
+ A. retain the following if it is supplied by the Licensor
+ with the Licensed Material:
+
+ i. identification of the creator(s) of the Licensed
+ Material and any others designated to receive attribution, in any
+ reasonable manner requested by the Licensor (including by pseudonym if
+ designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of
+ warranties;
+
+ v. a URI or hyperlink to the Licensed Material to the
+ extent reasonably practicable;
+
+ B. indicate if You modified the Licensed Material and retain
+ an indication of any previous modifications; and
+
+ C. indicate the Licensed Material is licensed under this
+ Public License, and include the text of, or the URI or hyperlink to, this
+ Public License.
+
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
+ reasonable manner based on the medium, means, and context in which You
+ Share the Licensed Material. For example, it may be reasonable to satisfy
+ the conditions by providing a URI or hyperlink to a resource that includes
+ the required information.
+
+ 3. If requested by the Licensor, You must remove any of the
+ information required by Section 3(a)(1)(A) to the extent reasonably
+ practicable.
+
+ b. ShareAlike.In addition to the conditions in Section 3(a), if You
+ Share Adapted Material You produce, the following conditions also apply.
+
+ 1. The Adapter’s License You apply must be a Creative Commons
+ license with the same License Elements, this version or later, or a
+ BY-NC-SA Compatible License.
+
+ 2. You must include the text of, or the URI or hyperlink to, the
+ Adapter's License You apply. You may satisfy this condition in any
+ reasonable manner based on the medium, means, and context in which You
+ Share Adapted Material.
+
+ 3. You may not offer or impose any additional or different terms
+ or conditions on, or apply any Effective Technological Measures to, Adapted
+ Material that restrict exercise of the rights granted under the Adapter's
+ License You apply.
+
+Section 4 – Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that apply to
+Your use of the Licensed Material:
+
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right to
+ extract, reuse, reproduce, and Share all or a substantial portion of the
+ contents of the database for NonCommercial purposes only;
+
+ b. if You include all or a substantial portion of the database
+ contents in a database in which You have Sui Generis Database Rights, then
+ the database in which You have Sui Generis Database Rights (but not its
+ individual contents) is Adapted Material, including for purposes of Section
+ 3(b); and
+
+ c. You must comply with the conditions in Section 3(a) if You Share
+ all or a substantial portion of the contents of the database.
+For the avoidance of doubt, this Section 4 supplements and does not replace
+Your obligations under this Public License where the Licensed Rights
+include other Copyright and Similar Rights.
+
+Section 5 – Disclaimer of Warranties and Limitation of Liability.
+
+ a. Unless otherwise separately undertaken by the Licensor, to the
+ extent possible, the Licensor offers the Licensed Material as-is and
+ as-available, and makes no representations or warranties of any kind
+ concerning the Licensed Material, whether express, implied, statutory, or
+ other. This includes, without limitation, warranties of title,
+ merchantability, fitness for a particular purpose, non-infringement,
+ absence of latent or other defects, accuracy, or the presence or absence of
+ errors, whether or not known or discoverable. Where disclaimers of
+ warranties are not allowed in full or in part, this disclaimer may not
+ apply to You.
+
+ b. To the extent possible, in no event will the Licensor be liable to
+ You on any legal theory (including, without limitation, negligence) or
+ otherwise for any direct, special, indirect, incidental, consequential,
+ punitive, exemplary, or other losses, costs, expenses, or damages arising
+ out of this Public License or use of the Licensed Material, even if the
+ Licensor has been advised of the possibility of such losses, costs,
+ expenses, or damages. Where a limitation of liability is not allowed in
+ full or in part, this limitation may not apply to You.
+
+ c. The disclaimer of warranties and limitation of liability provided
+ above shall be interpreted in a manner that, to the extent possible, most
+ closely approximates an absolute disclaimer and waiver of all liability.
+
+Section 6 – Term and Termination.
+
+ a. This Public License applies for the term of the Copyright and
+ Similar Rights licensed here. However, if You fail to comply with this
+ Public License, then Your rights under this Public License terminate
+ automatically.
+
+ b. Where Your right to use the Licensed Material has terminated under
+ Section 6(a), it reinstates:
+
+ 1. automatically as of the date the violation is cured, provided
+ it is cured within 30 days of Your discovery of the violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+ c. For the avoidance of doubt, this Section 6(b) does not affect any
+ right the Licensor may have to seek remedies for Your violations of this
+ Public License.
+
+ d. For the avoidance of doubt, the Licensor may also offer the
+ Licensed Material under separate terms or conditions or stop distributing
+ the Licensed Material at any time; however, doing so will not terminate
+ this Public License.
+
+ e. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+ License.
+
+Section 7 – Other Terms and Conditions.
+
+ a. The Licensor shall not be bound by any additional or different
+ terms or conditions communicated by You unless expressly agreed.
+
+ b. Any arrangements, understandings, or agreements regarding the
+ Licensed Material not stated herein are separate from and independent of
+ the terms and conditions of this Public License.
+
+Section 8 – Interpretation.
+
+ a. For the avoidance of doubt, this Public License does not, and shall
+ not be interpreted to, reduce, limit, restrict, or impose conditions on any
+ use of the Licensed Material that could lawfully be made without permission
+ under this Public License.
+
+ b. To the extent possible, if any provision of this Public License is
+ deemed unenforceable, it shall be automatically reformed to the minimum
+ extent necessary to make it enforceable. If the provision cannot be
+ reformed, it shall be severed from this Public License without affecting
+ the enforceability of the remaining terms and conditions.
+
+ c. No term or condition of this Public License will be waived and no
+ failure to comply consented to unless expressly agreed to by the Licensor.
+
+ d. Nothing in this Public License constitutes or may be interpreted as
+ a limitation upon, or waiver of, any privileges and immunities that apply
+ to the Licensor or You, including from the legal processes of any
+ jurisdiction or authority.
+
+Creative Commons is not a party to its public licenses. Notwithstanding,
+Creative Commons may elect to apply one of its public licenses to material
+it publishes and in those instances will be considered the “Licensor.”
+Except for the limited purpose of indicating that material is shared under
+a Creative Commons public license or as otherwise permitted by the Creative
+Commons policies published at creativecommons.org/policies, Creative
+Commons does not authorize the use of the trademark “Creative Commons”
+or any other trademark or logo of Creative Commons without its prior
+written consent including, without limitation, in connection with any
+unauthorized modifications to any of its public licenses or any other
+arrangements, understandings, or agreements concerning use of licensed
+material. For the avoidance of doubt, this paragraph does not form part of
+the public licenses.
+
+Creative Commons may be contacted at creativecommons.org.
--- /dev/null
+title: Michael Wallner (m6w6)
+blog: "Mike's sudden inspirations"
+email: mike@php.net
+description: >-
+ C/C++ writer.
+ PHP partisan.
+ Postgres fan.
+ GNU/Linux hacker.
+ Webophilic op.
+ <br>
+ Father of two.
+ Wide open throttle.
+ Photographer in another life.
+baseurl: "/"
+url: "" # the base hostname & protocol for your site, e.g. http://example.com
+twitter_username: _m6w6
+github_username: m6w6
+
+# Build settings
+#theme: minima
+plugins:
+ - jekyll-feed
+ - jekyll-relative-links
+ - jekyll-sitemap
+
+relative_links:
+ enabled: true
+ collections: true
+
+kramdown:
+ input: GFM
+ syntax_highlighter_opts:
+ default_lang: shell
+# css_class: 'highlight'
+ span:
+ line_numbers: false
+ block:
+ line_numbers: false
+ start_line: 1
+
+defaults:
+ -
+ scope:
+ path: ""
+ type: "posts"
+ values:
+ layout: "post"
+ permalink: ":year/:month/:title.html"
+ styles:
+ - "assets/post.css"
+ - "assets/rouge.css"
+
+# Exclude from processing.
+# The following items will not be processed, by default.
+# Any item listed under the `exclude:` key here will be automatically added to
+# the internal "default list".
+#
+# Excluded items can be processed by explicitly listing the directories or
+# their entries' file path in the `include:` list.
+#
+exclude:
+# - .sass-cache/
+# - .jekyll-cache/
+# - gemfiles/
+# - Gemfile
+# - Gemfile.lock
+# - node_modules/
+# - vendor/
+# - vendor/cache/
+# - vendor/gems/
+# - vendor/ruby/
+ - "[Gg]em*"
+ - ".idea/"
+ - "vendor/"
+ - "*cache*/"
+ - "node*/"
+
--- /dev/null
+<p class="cc-sa">
+
+ 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>.
+
+ <br>
+ <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"
+ ><img alt="Creative Commons Share Alike License" src="assets/cc-sa.png"
+ ></a>
+
+</p>
--- /dev/null
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="utf8">
+ <title>{{ page.title }} — {{ site.title }}</title>
+ <meta name="robots" content="index, follow">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <base href="{{ site.baseurl }}">
+ {% feed_meta %}
+ <link rel="icon" href="m6w6.png">
+{% for style in page.styles %}
+ <link rel="stylesheet" href="{{ style }}">
+{% endfor %}
+
+{% for script in page.scripts %}
+ <script src="{{ script }}" async></script>
+{% endfor %}
+ <style>body { display: none }</style>
+ </head>
--- /dev/null
+ <div class="pubinfo">
+ <p>
+ Posted by <em>{{ page.author }}</em>
+ on {{ page.date | date_to_long_string: "ordinal" }}
+ in <a href="blog.html">{{ site.blog }}</a>:
+ {% assign last_tag = page.tags | last %}
+ {% for tag in page.tags %}
+ <a class="tag" href="@{{ tag }}.html"
+ >{{ tag }}</a>{% if tag != last_tag %}, {% endif %}
+ {% endfor %}
+ </p>
+ </div>
--- /dev/null
+{% include head.html %}
+ <body class="default">
+ <div>
+ {{ content }}
+ </div>
+ </body>
+{% include foot.html %}
--- /dev/null
+{% include head.html %}
+
+<body class="post">
+
+<div>
+ <header>
+ <h1>{{ page.title }}</h1>
+ <div aria-hidden="true">
+ <span title="minimize">_</span>
+ <span title="maximize">☐</span>
+ <span title="close">☒</span>
+ </div>
+ </header>
+ <main>
+ <div>
+ {% include pubinfo.html %}
+ {{ content }}
+ </div>
+ </main>
+</div>
+
+<footer>
+ {% include ccsa.html %}
+</footer>
+
+</body>
+
+{% include foot.html %}
--- /dev/null
+---
+layout: default
+styles: assets/index.css
+---
+<header>
+ <h1>{{ page.title }}</h1>
+ <p class="breadcrumbs">
+ » <a href="blog.html">{{ site.blog }}</a>
+ </p>
+</header>
+<main>
+ <h2>#{{ page.tag }}</h2>
+ <ul>
+ {% for post in site.posts %}
+ {% if post.tags contains page.tag %}
+ <li>
+ <a class="post" href="{{ post.url }}">{{ post.title }}</a>
+ — posted {{ post.date | date_to_long_string: "ordinal" }}
+ </li>
+ {% endif %}
+ {% endfor %}
+ </ul>
+ <h2>See also</h2>
+ <p>
+ Posts in
+ {% assign last_tag = page.all_tags | last %}
+ {% for tag in page.all_tags %}
+ {% if tag != page.tag %}
+ {% if tag == last_tag %}
+ and
+ {% endif %}
+ <a class="tag" href="@{{ tag }}.html"
+ >{{ tag }}</a>{% if tag != last_tag %}, {% endif %}
+ {% endif %}
+ {% endfor %}
+ </p>
+</main>
--- /dev/null
+module Tags
+ class TagPageGenerator < Jekyll::Generator
+ safe true
+
+ def generate(site)
+ tags = site.posts.docs.flat_map { |post| post.data['tags'] || [] }.uniq
+ tags.to_set.each do |tag|
+ site.pages << TagPage.new(site, site.source, tag, tags)
+ end
+ end
+ end
+
+ class TagPage < Jekyll::Page
+ def initialize(site, base, tag, tags)
+ @site = site
+ @base = base
+ @dir = ""
+ @name = "@#{tag}.html"
+
+ self.process(@name)
+ self.read_yaml(base, File.join("_layouts", "tags.html"))
+ self.data['tag'] = tag
+ self.data['title'] = "Posts in #{tag}"
+ self.data['permalink'] = "@#{tag}.html"
+ self.data['all_tags'] = tags
+ end
+ end
+end
--- /dev/null
+---
+title: Javascript & Flexy
+author: m6w6
+tags:
+- PHP
+---
+
+If you ever used [Flexy](http://pear.php.net/package/HTML_Template_Flexy),
+which I consider a really great TE, you have most probably already stumbled
+across Flexy's inability to step into `<script>` blocks.
+
+A really easy method to overcome this problem is to define scriptOpen and
+scriptClose properties in your base objects outputted by Flexy:
+
+```php
+<?php
+class FlexyObject {
+ var $scriptOpen = "\n<script type="text/javascript"> <!--\n";
+ var $scriptClose = "\n//--> </script>n";
+ var $scriptData = "var foo = 'bar';";
+}
+```
+
+Outputting above object with the following template wont work:
+
+```html
+<html>
+<script type="text/javascript">
+ {scriptData:h}
+</script>
+</html>
+```
+
+Instead:
+
+```html
+<html>
+{scriptOpen:h}
+ {scriptData:h}
+{scriptClose:h}
+</html>
+```
+
+...works like a charm... ;)
+
+Alan said, Flexy wont step into Javascript blocks because that caused
+massive problems with the Smarty convertor...
--- /dev/null
+---
+title: Scrollable overflow:auto Elements in Mozilla
+author: m6w6
+tags:
+- WEB
+---
+
+Doing some extensive Javascript work lately, I managed to make HTML elements
+styled with //overflow:auto// scrollable in Mozilla.
+
+
+
+Just place this snippet at the bottom of your page with DIV elements that have
+scroll as classname:
+
+
+```js
+// enable scrolling for overflow:auto elements in Mozilla
+function scrollMe(event)
+{
+ var st = event.currentTarget.scrollTop;
+ st += (event.detail * 12);
+ event.currentTarget.scrollTop = st < 0 ? 0 : st;
+ event.preventDefault();
+}
+if (document.body.addEventListener) {
+ var divs = document.getElementsByTagName('DIV');
+ for (var d in divs) {
+ if (divs[d].className && divs[d].className == 'scroll') {
+ try {
+ divs[d].addEventListener(
+ 'DOMMouseScroll', scrollMe, false);
+ } catch (ex) {}
+ }
+ }
+}
+```
+
+
+I already posted a feature request to embed something similar in pearweb.
--- /dev/null
+---
+title: Class inheritance or Containers?
+author: m6w6
+tags:
+- PHP
+---
+
+While talking with Daniel and Lorenzo about "Tree Reincarnated" I regularly
+stumble across the question what approach to use to implement different
+backends: **"Class inheritance or Containers?"**.
+
+I personally feel that using the container approach leads to massive code
+duplication, while using class inheritance avoids the most (_most_, because
+there's no real multiple class inheritance in PHP).
+
+## Container
+```php
+ class PublicAPI
+ {
+ var $container; // SpecificAPI
+
+ function doSomething()
+ {
+ return $this->container->doSomething();
+ }
+ }
+```
+
+## Class Inheritance
+
+```php
+ class SpecificAPI extends PublicAPI
+ {
+ function doSomething()
+ {
+ // do something only this class needs to do
+ }
+ }
+ ?>
+```
+
+So what do you feel about this topic and how you'd handle that?
+
+## UPDATE
+
+While looking again at Daniel's [nice diagram](http://devel.webcluster.at/~daniel/pear/Tree/docs/Tree.png?),
+I feel like we've already reached the point where solving this problem with class
+inheritence is impossible (despite using aggregate*() - you're right Lorenzo,
+again :) have nice holidays! ).
+
+Tree_Admin_Simple_MDB2 would have to extend Tree_Simple_MDB2 **and**
+Tree_Admin_Simple_RDBMS...
+
+Mike's arrived at the dead end, again ;)
--- /dev/null
+---
+title: Dropping server load with HTTP caching
+author: m6w6
+tags:
+- PHP
+---
+
+Ever watched youself browsing e.g. a web forum?
+Noticed that you viewed the same page several times?
+
+Well, this means extraordinary **and** useless load for your server if there's
+no caching mechanism implemented in the web application. Even if there is some
+file or db cache you can still improve performance with implementing some http
+cache.
+
+The easiest way is using PEARs
+[HTTP::Header](http://pear.php.net/package/HTTP_Header):
+
+```php
+require_once 'HTTP/Header/Cache.php';
+// only cache a few seconds for frequently
+// changing pages like a forum;
+// Header_Cache will exit automatically with
+// "HTTP 304 Not Modified" if the page is
+// requested twice within 3 seconds
+$cache = &new HTTP_Header_Cache(3, 'seconds');
+$cache->sendHeaders();
+
+// ... load from file/db cache
+// ... or rebuild page
+```
+
+~~Probably the greatest caveat of using HTTP caching is, that our _beloved_
+Internet Explorer with standard settings doesn't even send an request to the
+server if it just **notices** a "Last-Modified" header (sic!), so one'd have
+to press the reload button (without CTRL) that a new page is displayed after
+the defined amount of time.~~
+
+~~A dead end again? Decide yourself...~~
+
+I finally managed to implement support for Internet Explorer in HTTP_Header
+1.1.0 :D
--- /dev/null
+---
+title: 'Update: overflow:auto in Mozilla'
+author: m6w6
+tags:
+- WEB
+---
+
+If you want the page to scroll when the scrolling-enabled DIV has nothing to
+scroll you'll have to wrap the contents of the _scrollMe_ function into the
+following **if** statement:
+
+```js
+ function scrollMe(event)
+ {
+ if (event.currentTarget.scrollHeight >
+ event.currentTarget.offsetHeight) {
+ // ...
+ }
+ }
+```
+
+Have fun!
--- /dev/null
+---
+title: ext/apr - exercise or joke?
+author: m6w6
+tags:
+- PHP
+---
+
+Well yes, it started as an exercise (and others thought it is a joke) ;)
+
+My intention was to export apr_md5_encode() to php which generates MD5
+password hashes similar to those found in .htpasswd files. [PEARs
+File_Passwd](http://pear.php.net/package/File_Passwd) already does that, but
+with plain vanilla PHP - generating one password takes about 0.2 seconds and
+more.
+
+Currently I'm trying to make apr_threads usable - wouldn't threads in PHP be
+cool? Yes, they'd definitly be :) It's just a segfault away from working ;)
+
+```php
+ class Thread1 extends APR_Thread {
+ function run() {
+ // do some work
+ }
+ }
+ class Thread2 extends APR_Thread {
+ function run() {
+ // do some concurrent work
+ }
+ }
+ new Thread1;
+ new Thread2;
+```
+
+Thanks to Derick, Sara and the whole php.pecl gang - I wouldn't have managed
+to get that far without their tremendous help!
--- /dev/null
+---
+title: HORDE::Chora major vulnaribility
+author: m6w6
+tags:
+- PHP
+---
+
+If you're running Hordes Chora **1.2** you should immediately upgrade your
+Horde installation or temporarily disable CVS access through HTTP.
+
+
+### Unfiltered $_GET as shell argument
+On a quick glance scripts like _diff.php_ seem to use unfiltered $_GET
+parameters as shell command arguments, which will allow any remote user to
+execute any command as webserver user.
+
+A request like ~~<http://cvs.your.host/>... ~~ will reveal the process list of
+the machine.
+
--- /dev/null
+---
+title: Chora already fixed
+author: m6w6
+tags:
+- PHP
+---
+
+[Jan](http://janschneider.de/cweb/home/index,channel,25,story,175.html)
+reported that Chora is already fixed for three months.
+
+
+First of all, let me apologize, I didn't want to hurt
+[Horde](http://horde.org) or anyone else, and if you found my posting
+confusing, then well, I was confused and not too little...
+
+That weekend my server has been cracked again, and ctorrent has been installed
+to burn my traffic (from the same network 210.5.125.*).
+
+I doubt that the
+[announcement](http://lists.horde.org/archives/announce/2004/000100.html) Jan
+posted helped much, because how comes that apparently every script-kiddy knew
+about the vulnaribility but not chora users (at least I didn't know, and I saw
+a lot of chora 1.2 installations out there).
+
+If I would have found a note on [Chora's homepage](http://www.horde.org/chora/),
+I think, I wouldn't have posted such a panic reaction.
+
+So, sorry once again and I hope that this was - at least - a lesson to
+everyone of us...
--- /dev/null
+---
+title: ext/vpopmail? no thanks...
+author: m6w6
+tags:
+- PHP
+---
+
+If you ever thought about administering vpopmail through PHP, you most
+probably already stumbled across the [vpopmail](http://pecl.php.net/vpopmail)
+extension living in [PECL](http://pecl.php.net/), and know that making use of
+it is rather kludgy...
+
+In need of such a solution I've written a simple XML-RPC CGI service in C with
+help of the [xmlrpc-c](http://xmlrpc-c.sourceforge.net/) library. I really
+didn't think that it would be that easy, but it definitely was, considering
+that I'm a C novice ;)
+
+The following source will show that it's quite as simple as writing this XML-
+RPC backend in PHP, and it's really fast.
+
+### Update
+There's now a source tarball available at: <http://dev.iworks.at/vpop-xmlrpc/>
+```c
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <vauth.h>
+#include <vpopmail.h>
+#include <xmlrpc.h>
+#include <xmlrpc_cgi.h>
+
+static xmlrpc_value *vpop_adduser(xmlrpc_env *env, xmlrpc_value *param, void *data)
+{
+ char *user, *domain, *password, *fullname;
+ xmlrpc_bool rs;
+
+ xmlrpc_parse_value(env, param, "({s:s,s:s,s:s,s:s,*})",
+ "user", &user,
+ "domain", &domain,
+ "password", &password,
+ "fullname", &fullname
+ );
+
+ if (env->fault_occurred) {
+ return NULL;
+ }
+
+ rs = vadduser(user, domain, password, fullname, 0) == 0 ? 1 : 0;
+
+ return xmlrpc_build_value(env, "b", rs);
+}
+
+static xmlrpc_value *vpop_deluser(xmlrpc_env *env, xmlrpc_value *param, void *data)
+{
+ char *user, *domain;
+ xmlrpc_bool rs;
+
+ xmlrpc_parse_value(env, param, "({s:s,s:s,*})",
+ "user", &user,
+ "domain", &domain
+ );
+
+ if (env->fault_occurred) {
+ return NULL;
+ }
+
+ rs = vdeluser(user, domain) == 0 ? 1 : 0;
+
+ return xmlrpc_build_value(env, "b", rs);
+}
+
+static xmlrpc_value *vpop_passwd(xmlrpc_env *env, xmlrpc_value *param, void *data)
+{
+ char *user, *domain, *password;
+ xmlrpc_bool rs;
+
+ xmlrpc_parse_value(env, param, "({s:s,s:s,s:s,*})",
+ "user", &user,
+ "domain", &domain,
+ "password", &password
+ );
+
+ if (env->fault_occurred) {
+ return NULL;
+ }
+
+ rs = vpasswd(user, domain, password, 0) == 0 ? 1 : 0;
+
+ return xmlrpc_build_value(env, "b", rs);
+}
+
+static xmlrpc_value *vpop_setquota(xmlrpc_env *env, xmlrpc_value *param, void *data)
+{
+ char *user, *domain, *quota;
+ xmlrpc_bool rs;
+
+ xmlrpc_parse_value(env, param, "({s:s,s:s,s:s,*})",
+ "user", &user,
+ "domain", &domain,
+ "quota", "a
+ );
+
+ if (env->fault_occurred) {
+ return NULL;
+ }
+
+ rs = vsetuserquota(user, domain, quota) == 0 ? 1 : 0;
+
+ return xmlrpc_build_value(env, "b", rs);
+}
+
+int main(int argc, char **argv)
+{
+ xmlrpc_cgi_init(XMLRPC_CGI_NO_FLAGS);
+
+ xmlrpc_cgi_add_method_w_doc("vpop.adduser", &vpop_adduser, NULL,
+ "b:S", "Add a vpopmail user to a domain with password, fullname and quota.");
+ xmlrpc_cgi_add_method_w_doc("vpop.deluser", &vpop_deluser, NULL,
+ "b:S", "Delete a user from a domain.");
+ xmlrpc_cgi_add_method_w_doc("vpop.passwd", &vpop_passwd, NULL,
+ "b:S", "Change the password of a user in a domain.");
+ xmlrpc_cgi_add_method_w_doc("vpop.setquota", &vpop_setquota, NULL,
+ "b:S", "Set the quota of a user in a domain.");
+
+ xmlrpc_cgi_process_call();
+
+ xmlrpc_cgi_cleanup();
+ return 0;
+}
+```
+
--- /dev/null
+---
+title: PEAR::Auth and vpop-xmlrpc
+author: m6w6
+tags:
+- PHP
+---
+
+You guessed, I've written a [vpop-xmlrpc container](http://dev.iworks.at/vpop-xmlrpc/VPOPXMLRPC.phps)
+for [PEAR::Auth](http://pear.php.net/package/Auth).
+
+There's also a [new version](http://dev.iworks.at/vpop-xmlrpc/vpop-xmlrpc-1.1.tar.gz)
+of the vpop-xmlrpc cgi, which is needed for the Auth
+container, because the method **vpop.auth** has recently been added.
+
+Have fun ;)
--- /dev/null
+---
+title: pecl_http
+author: m6w6
+tags:
+- PHP
+---
+
+I just released the new [http](http://pecl.php.net/package/pecl_http/) PECL
+package.
+
+It's named pecl_http because there's already an HTTP package in PEAR.
+Hopefully channels will be available soon ;)
+
+There are for sure lots of bugs in it, but give it a try anyway... :)
+
--- /dev/null
+---
+title: PECL::HTTP 0.6.0
+author: m6w6
+tags:
+- PHP
+---
+
+I just released [pecl_http](http://pecl.php.net/package/pecl_http/) 0.6.0! ;)
+
+For its current capabilities you should have a look at
+[this](http://dev.iworks.at/ext-http/http-functions.html.gz) document.
+
+Don't hesitate to leave a comment, or drop [me](mailto:mike@php.net) a mail if
+you've got questions!
+
--- /dev/null
+---
+title: mod_domaintree
+author: m6w6
+tags:
+- PHP
+---
+
+Friday evening I put together a tiny [Apache2](http://httpd.apache.org) module
+simliar to mod_vhost_alias or mod_vd.
+[mod_domaintree](http://cvs.iworks.at/co.php/mod_domaintree/mod_domaintree.c)
+maps host names to a filesystem tree. While mod_vhost_alias and mod_vd seem to
+be more flexible, they seem less useful to me.
+
+mod_vhost_alias lets you define very precisely which part of the host name
+maps to which directory but adds odd underscores if the part (number) of the
+hostname does not exist.
+
+mod_vd lets you define the numerical amount of host name parts to strip.
+
+But I **don't want to strip always** one part of the host name like "www" \- I
+just want to strip the first part of the host name (i.e. www) if it occurs in
+the sent hostname.
+
+If you want to try it out, there's nothing more to do then (w)getting
+[it](http://cvs.iworks.at/co.php/mod_domaintree/mod_domaintree.c?p=1) and
+running
+```shell
+sudo /usr/sbin/apxs2 -a -i -c mod_domaintree.c
+```
+## Sample Configuration:
+```apache
+DomainTreeEnabled On
+DomainTreeMaxdepth 25
+DomainTreeStripWWW On
+DomainTreePrefix /sites
+DomainTreeSuffix /html
+```
+
+### Mapped Hosts: (accepting "www" as prefix if DomainTreeStripWWW is enabled)
+
+ * company.co.at
+ * sub1.company.co.at
+ * sub2.company.co.at
+ * organisation.or.at
+ * example.at
+ * example.com
+
+### Resulting Filesystem Tree:
+```shell
+ /sites
+ +- /at
+ | +- /co
+ | | +- /company
+ | | +- /html
+ | | +- /sub1
+ | | | +- /html
+ | | +- /sub2
+ | | +- /html
+ | +- /or
+ | | +- /organisation
+ | | +- /html
+ | +- /example
+ | +- /html
+ +- /com
+ +- /example
+ +- /html
+```
+
+PS: I was very suprised how easy it is to build a simple module for Apache (if
+you have some templates to look at though). :)
--- /dev/null
+---
+title: HttpRequestPool in PECL::HTTP
+author: m6w6
+tags:
+- PHP
+---
+
+I just checked in a first working version of HttpRequestPool into CVS.
+It's curl_multi that's doing its job underneath and is used tp send several
+HttpRequests at once.
+```php
+$urls = array(
+ 'http://www.php.net/',
+ 'http://pear.php.net/',
+ 'http://pecl.php.net/'
+);
+
+$pool = new HttpRequestPool;
+foreach ($urls as $url) {
+ $pool->attach(new HttpRequest($url, HTTP_METH_HEAD));
+}
+
+try {
+ $pool->send();
+ foreach ($pool as $r) {
+ $status = $r->getResponseCode();
+ printf("%-20s is %sn",
+ $r->getUrl(),
+ $status == 200 ? "ALIVE" : "NOT OK ($status)"
+ );
+ }
+} catch (HttpException $ex) {
+ echo $ex;
+}
+```
--- /dev/null
+---
+title: Is PHP staying the language I want to work with?
+author: m6w6
+tags:
+- PHP
+---
+
+While some of the core PHP internals already see theirself that there's
+something wrong with the so-called generic way ZE2 looks up classes, many
+stolidly ignore the claims of PHP users...
+
+Look at this [MARC Thread](http://marc.info/?t=111887022700001&r=1&w=2) and that
+[MARC Thread](http://marc.info/?t=111999411200002&r=1&w=2).
+
+[Now something to laugh (or cry) at](http://marc.info/?l=pear-cvs&m=111999141214948&w=2)
+
+WTF?
--- /dev/null
+---
+title: PECL HTTP, lap 12
+author: m6w6
+tags:
+- PHP
+---
+
+Today I released [PECLs HTTP extension version 0.12](http://pecl.php.net/package/pecl_http/0.12.0)
+
+A lot of work and fixes have gone into it, and I hope it's becoming stable
+even this century ;)
+
+Major changes are a general API cleanup where AuthBasic hooks have been
+removed and many HttpRequest methods have been sanitized.
+
+The HttpResponse class should now work with PHP5 as a webserver module as well
+and should not any longer have hard dependencies on ext/session and ext/zlib.
+
+Additionally, if you have libmhash (note: not necessarily ext/mhash) you can
+choose a hashing algorithm provided by libmhash to generate your ETags, which
+is done through the following INI setting: http.etag_mode = MHASH_SHA256
+(MHASH_SHA256 is an example and can be replaced by any MHASH constant **if**
+you have ext/mhash).
+
+The message and header parsers have been vastly improved to be able to parse
+(in principle invalid) messages and headers that only have a single LF instead
+of CRLF.
+
+And last but not least it should again flawlessly build for PHP4.
+
+So far, have fun and be sure to check it out! :)
+
--- /dev/null
+---
+title: Tutorial -kinda- for pecl/http
+author: m6w6
+tags:
+- PHP
+---
+
+I've added a tiny tutorial, or sort of collection of usage examples,
+to the pecl/http repository.
+
+You can read it in the extended post, or just check it out from CVS.
+Please note that the code for the XMLRPC client has just been put into CVS.
+
+## GET Queries
+
+The HttpRequest class can be used to execute any HTTP request method.
+The following example shows a simple GET request where a few query
+parameters are supplied. Additionally potential cookies will be read
+from and written to a file.
+
+```php
+$r = new HttpRequest('http://www.google.com');
+
+// store Googles cookies in a dedicated file
+$r->setOptions(
+ array( 'cookiestore' => '../cookies/google.txt',
+ )
+);
+
+$r->setQueryData(
+ array( 'q' => '+"pecl_http" -msg -cvs -list',
+ 'hl' => 'de'
+ )
+);
+
+// HttpRequest::send() returns an HttpMessage object
+// of type HttpMessage::TYPE_RESPONSE or throws an exception
+try {
+ print $r->send()->getBody();
+} catch (HttpException $e) {
+ print $e;
+}
+```
+
+## Multipart Posts
+
+
+The following example shows an multipart POST request, with two form
+fields and an image that's supposed to be uploaded to the server.
+
+It's a bad habit as well as common practice to issue a redirect after
+an received POST request, so we'll allow a redirect by enabling the
+redirect option.
+
+```php
+$r = new HttpRequest('http://dev.iworks.at/.print_request.php',
+ HTTP_METH_POST);
+
+// if redirects is set to true, a single redirect is allowed;
+// one can set any reasonable count of allowed redirects
+$r->setOptions(
+ array( 'cookies' => array('MyCookie' => 'has a value'),
+ 'redirect' => true,
+ )
+);
+
+// common form data
+$r->setPostFields(
+ array( 'name' => 'Mike',
+ 'mail' => 'mike@php.net',
+ )
+);
+// add the file to post (form name, file name, file type)
+$r->addPostFile('image', 'profile.jpg', 'image/jpeg');
+
+try {
+ print $r->send()->getBody();
+} catch (HttpException $e) {
+ print $e;
+}
+```
+
+## Parallel Requests
+
+It's possible to execute several HttpRequests in parallel with the
+HttpRequestPool class. HttpRequests to send, do not need to perform
+the same request method, but can only be attached to one HttpRequestPool
+at the same time.
+
+```php
+try {
+ $p = new HttpRequestPool;
+ // if you want to set _any_ options of the HttpRequest object,
+ // you need to do so *prior attaching* to the request pool!
+ $p->attach(new HttpRequest('http://pear.php.net',
+ HTTP_METH_HEAD));
+ $p->attach(new HttpRequest('http://pecl.php.net',
+ HTTP_METH_HEAD));
+} catch (HttpException $e) {
+ print $e;
+ exit;
+}
+
+try {
+ $p->send();
+ // HttpRequestPool implements an iterator
+ // over attached HttpRequest objects
+ foreach ($p as $r) {
+ echo "Checking ", $r->getUrl(), " reported ",
+ $r->getResponseCode(), "\n";
+ }
+} catch (HttpException $e) {
+ print $e;
+}
+```
+
+### Parallel Requests?
+
+You can use a more advanced approach by using the protected interface of
+the HttpRequestPool class. This allows you to perform some other tasks
+while the requests are executed.
+
+```php
+class Pool extends HttpRequestPool
+{
+ public function __construct()
+ {
+ parent::__construct(
+ new HttpRequest('http://pear.php.net',
+ HTTP_METH_HEAD),
+ new HttpRequest('http://pecl.php.net',
+ HTTP_METH_HEAD)
+ );
+
+ // HttpRequestPool methods socketPerform() and
+ // socketSelect() are protected; one could use
+ // this approach to do something else
+ // while the requests are being executed
+ print "Executing requests";
+ for ($i = 0; $this->socketPerform(); $i++) {
+ $i % 10 or print ".";
+ if (!$this->socketSelect()) {
+ throw new HttpException("Socket error!");
+ }
+ }
+ print "nDone!n";
+ }
+}
+
+try {
+ foreach (new Pool as $r) {
+ echo "Checking ", $r->getUrl(), " reported ",
+ $r->getResponseCode(), "\n";
+ }
+} catch (HttpException $ex) {
+ print $e;
+}
+```
+
+## Cached Responses
+
+One of the main key features of HttpResponse is HTTP caching. HttpResponse
+will calculate an ETag based on the http.etag_mode INI setting as well as
+it will determine the last modification time of the sent entity. It uses
+those two indicators to decide if the cache entry on the client side is
+still valid and will emit an "304 Not Modified" response if applicable.
+
+```php
+HttpResponse::setCacheControl('public');
+HttpResponse::setCache(true);
+HttpResponse::capture();
+
+print "This will be cached until content changes!\n";
+print "Note that this approach will only save the clients download time.\n";
+```
+
+## Bandwidth Throttling
+
+HttpResponse supports a basic throttling mechanism, which is enabled by
+setting a throttle delay and a buffer size. PHP will sleep the specified
+amount of seconds after each sent chunk of specified bytes.
+
+```php
+// send 5000 bytes every 0.2 seconds, i.e. max ~25kByte/s
+HttpResponse::setThrottleDelay(0.2);
+HttpResponse::setBufferSize(5000);
+HttpResponse::setCache(true);
+HttpResponse::setContentType('application/x-zip');
+HttpResponse::setFile('../archive.zip');
+HttpResponse::send();
+```
+
+## KISS XMLRPC Client
+
+```php
+class XmlRpcClient
+{
+ public $namespace;
+ protected $request;
+
+ public function __construct($url, $namespace = '')
+ {
+ $this->namespace = $namespace;
+ $this->request = new HttpRequest($url, HTTP_METH_POST);
+ $this->request->setContentType('text/xml');
+ }
+
+ public function setOptions($options = array())
+ {
+ return $this->request->setOptions($options);
+ }
+
+ public function addOptions($options)
+ {
+ return $this->request->addOptions($options);
+ }
+
+ public function __call($method, $params)
+ {
+ if ($this->namespace) {
+ $method = $this->namespace .'.'. $method;
+ }
+ $this->request->setRawPostData(
+ xmlrpc_encode_request($method, $params));
+ $response = $this->request->send();
+ if ($response->getResponseCode() != 200) {
+ throw new Exception($response->getBody(),
+ $response->getResponseCode());
+ }
+ return xmlrpc_decode($response->getBody(), 'utf-8');
+ }
+
+ public function getHistory()
+ {
+ return $this->request->getHistory();
+ }
+}
+```
+
+## Simple Feed Aggregator
+
+```php
+class FeedAggregator
+{
+ public $directory;
+ protected $feeds = array();
+
+ public function __construct($directory = 'feeds')
+ {
+ $this->setDirectory($directory);
+ }
+
+ public function setDirectory($directory)
+ {
+ $this->directory = $directory;
+ foreach (glob($this->directory .'/*.xml') as $feed) {
+ $this->feeds[basename($feed, '.xml')] = filemtime($feed);
+ }
+ }
+
+ public function url2name($url)
+ {
+ return preg_replace('/[^w.-]+/', '_', $url);
+ }
+
+ public function hasFeed($url)
+ {
+ return isset($this->feeds[$this->url2name($url)]);
+ }
+
+ public function addFeed($url)
+ {
+ $r = $this->setupRequest($url);
+ $r->send();
+ $this->handleResponse($r);
+ }
+
+ public function addFeeds($urls)
+ {
+ $pool = new HttpRequestPool;
+ foreach ($urls as $url) {
+ $pool->attach($r = $this->setupRequest($url));
+ }
+ $pool->send();
+
+ foreach ($pool as $request) {
+ $this->handleResponse($request);
+ }
+ }
+
+ public function getFeed($url)
+ {
+ $this->addFeed($url);
+ return $this->loadFeed($this->url2name($url));
+ }
+
+ public function getFeeds($urls)
+ {
+ $feeds = array();
+ $this->addFeeds($urls);
+ foreach ($urls as $url) {
+ $feeds[] = $this->loadFeed($this->url2name($url));
+ }
+ return $feeds;
+ }
+
+ protected function saveFeed($file, $contents)
+ {
+ if (file_put_contents($this->directory .'/'. $file .'.xml', $contents)) {
+ $this->feeds[$file] = time();
+ } else {
+ throw new Exception(
+ "Could not save feed contents to $file.xml");
+ }
+ }
+
+ protected function loadFeed($file)
+ {
+ if (isset($this->feeds[$file])) {
+ if ($data = file_get_contents($this->directory .'/'. $file .'.xml')) {
+ return $data;
+ } else {
+ throw new Exception(
+ "Could not load feed contents from $file.xml");
+ }
+ } else {
+ throw new Exception("Unknown feed/file $file.xml");
+ }
+ }
+
+ protected function setupRequest($url)
+ {
+ $r = new HttpRequest($url);
+ $r->setOptions(array('redirect' => true));
+
+ $file = $this->url2name($url);
+
+ if (isset($this->feeds[$file])) {
+ $r->setOptions(array('lastmodified' => $this->feeds[$file]));
+ }
+
+ return $r;
+ }
+
+ protected function handleResponse(HttpRequest $r)
+ {
+ if ($r->getResponseCode() != 304) {
+ if ($r->getResponseCode() != 200) {
+ throw new Exception("Unexpected response code ".
+ $r->getResponseCode());
+ }
+ if (!strlen($body = $r->getResponseBody())) {
+ throw new Exception("Received empty feed from ".
+ $r->getUrl());
+ }
+ $this->saveFeed($this->url2name($r->getUrl()), $body);
+ }
+ }
+}
+```
--- /dev/null
+---
+title: References in PHP
+author: m6w6
+tags:
+- PHP
+---
+
+Derick made his article about variable references - published in
+[PHP Architect](http://www.phparch.com/)s June edition -
+[available online](http://derickrethans.nl/php_references_article.php).
+
+If you ever wanted to know how variables and references in PHP **look like** ,
+this read is a MUST.
--- /dev/null
+---
+title: Obviously...
+author: m6w6
+tags:
+- WTF
+---
+
+[...morons don't die off](http://bugs.php.net/bug.php?id=35208)
--- /dev/null
+---
+title: PHP-5.1 around the corner
+author: m6w6
+tags:
+- PHP
+---
+
+Here's a tidied up excerpt of the current NEWS file with all relevant changes
+since PHP 5.0, which may help on the decision to upgrade (even from PHP 4 :))
+
+### Fixes
+
+ * More than 350
+
+### Changes
+
+ * Changed PDO constants to class constants (PDO::CONST_NAME)
+ * Changed SQLite extension to be a shared module in Windows distribution
+ * Changed "instanceof" and "catch" operators, [is_a](http://php.net/is_a)() and [is_subclass_of](http://php.net/is_subclass_of)() functions to not call [__autoload](http://php.net/__autoload)()
+ * Changed [sha1_file](http://php.net/sha1_file)() and [md5_file](http://php.net/md5_file)() functions to use streams instead of low level IO
+ * Changed abstract private methods to be not allowed anymore
+ * Changed [stream_filter_(ap|pre)pend](http://php.net/stream_filter_append)() to return resource
+ * Changed mysqli_exception and sqlite_exception to use RuntimeException as base if SPL extension is present
+
+### Extensions moved to [PECL](http://pecl.php.net)
+
+ * cpdf
+ * dio
+ * fam
+ * ingres_ii
+ * mcve
+ * mnogosearch
+ * oracle
+ * ovrimos
+ * pfpro
+ * w32api
+ * yp
+
+### Upgraded [PEAR](http://pear.php.net)
+
+ * to channel-featuring v1.4### Upgraded bundled libraries
+
+### Upgraded bundled libraries
+
+ * PCRE library to version 6.2
+ * SQLite 3 library in ext/pdo_sqlite to 3.2.7
+ * SQLite 2 library in ext/sqlite to 2.8.16### Upgraded bundled libraries in Windows distribution
+
+### Upgraded bundled libraries in Windows distribution
+ * zlib 1.2.3
+ * curl 7.14.0
+ * openssl 0.9.8
+ * ming 0.3b
+ * libpq (PostgreSQL) 8.0.1
+
+### Improvements and Additions
+
+ * Improved SPL extension
+ * Moved RecursiveArrayIterator from examples into extension
+ * Moved RecursiveFilterIterator from examples into extension
+ * Added SplObjectStorage
+ * Made all SPL constants class constants
+ * Renamed CachingRecursiveIterator to RecursiveCachingIterator to follow Recursive<*>Iterator naming scheme
+ * Added support for class constants and static members for internal classes
+ * Added PDO::MYSQL_ATTR_USE_BUFFERED_QUERY parameter for pdo_mysql
+ * Added [date_timezone_set](http://php.net/date_timezone_set)() function to set the timezone that the date functions will use
+ * Added [pg_fetch_all_columns](http://php.net/pg_fetch_all_columns)() function to fetch all values of a column from a result cursor
+ * Added support for LOCK_EX flag for [file_put_contents](http://php.net/file_put_contents)()
+ * Implemented feature request [#33452](http://bugs.php.net/33452)
+ * Improved PHP extension loading mechanism with support for module dependencies and conflicts
+ * Allowed return by reference from internal functions
+ * Rewrote [strtotime](http://php.net/strtotime)() with support for timezones and many new formats. Implements feature requests [#21399](http://bugs.php.net/21399), [#26694](http://bugs.php.net/26694), [#28088](http://bugs.php.net/28088), [#29150](http://bugs.php.net/29150), [#29585](http://bugs.php.net/29585) and [#29595](http://bugs.php.net/29595)
+ * Added bindto socket context option
+ * Added offset parameter to the [stream_copy_to_stream](http://php.net/stream_copy_to_stream)() function
+ * Added offset & length parameters to [substr_count](http://php.net/substr_count)() function
+ * Removed [php_check_syntax](http://php.net/php_check_syntax)() function which never worked properly
+ * Removed garbage manager in Zend Engine which results in more aggressive freeing of data
+ * [Improved interactive mode of PHP CLI](http://blog.thinkphp.de/archives/44-More-PHP-power-on-the-command-line.html)
+ * Improved performance of:
+ * general execution/compilation
+ * [switch](http://php.net/switch)() statement
+ * several array functions
+ * virtual path handling by adding a [realpath](http://php.net/realpath)() cache
+ * variable fetches
+ * magic method invocations
+ * Improved support for embedded server in mysqli
+ * Improved mysqli extension
+ * added constructor for mysqli_stmt and mysqli_result classes
+ * added new function [mysqli_get_charset](http://php.net/mysqli_get_charset)()
+ * added new function [mysqli_set_charset](http://php.net/mysqli_set_charset)()
+ * added new class mysqli_driver
+ * added new class mysqli_warning
+ * added new class mysqli_execption
+ * added new class mysqli_sql_exception
+ * Improved SPL extension
+ * added standard hierarchy of Exception classes
+ * added interface Countable
+ * added interfaces Subject and Observer
+ * added spl_autoload*() functions
+ * converted several 5.0 examples into c code
+ * added class FileObject
+ * added possibility to use a string with [class_parents](http://php.net/class_parents)() and [class_implements](http://php.net/class_implements)()
+ * Added man pages for "phpize" and "php-config" scripts
+ * Added support for .cc files in extensions
+ * Added PHP_INT_MAX and PHP_INT_SIZE as predefined constants
+ * Added user opcode API that allow overloading of opcode handlers
+ * Added an optional remove old session parameter to [session_regenerate_id](http://php.net/session_regenerate_id)()
+ * Added array type hinting
+ * Added the [tidy_get_opt_doc](http://php.net/tidy_get_opt_doc)() function to return documentation for configuration options in tidy
+ * Added support for .cc files in extensions
+ * Added [imageconvolution](http://php.net/imageconvolution)() function which can be used to apply a custom 3x3 matrix convolution to an image
+ * Added optional first parameter to XsltProcessor::registerPHPFunctions to only allow certain functions to be called from XSLT
+ * Added the ability to override the autotools executables used by the buildconf script via the PHP_AUTOCONF and PHP_AUTOHEADER environmental variables
+ * Added several new functions to support the PostgreSQL v3 protocol introduced in PostgreSQL 7.4
+ * [pg_transaction_status](http://php.net/pg_transaction_status)() - in-transaction status of a database connection
+ * [pg_query_params](http://php.net/pg_query_params)() - execution of parameterized queries
+ * [pg_prepare](http://php.net/pg_prepare)() - prepare named queries
+ * [pg_execute](http://php.net/pg_execute)() - execution of named prepared queries
+ * [pg_send_query_params](http://php.net/pg_send_query_params)() - async equivalent of [pg_query_params](http://php.net/pg_query_params)()
+ * [pg_send_prepare](http://php.net/pg_send_prepare)() - async equivalent of [pg_prepare](http://php.net/pg_prepare)()
+ * [pg_send_execute](http://php.net/pg_send_execute)() - async equivalent of [pg_execute](http://php.net/pg_execute)()
+ * [pg_result_error_field](http://php.net/pg_result_error_field)() - highly detailed error information, most importantly the SQLSTATE error code
+ * [pg_set_error_verbosity](http://php.net/pg_set_error_verbosity)() - set verbosity of errors
+ * Added optional fifth parameter "count" to [preg_replace_callback](http://php.net/preg_replace_callback)() and [preg_replace](http://php.net/preg_replace)() to count the number of replacements made. FR [#32275](http://bugs.php.net/32275)
+ * Added optional third parameter "charlist" to [str_word_count](http://php.net/str_word_count)() which contains characters to be considered as word part. FR [#31560](http://bugs.php.net/31560)
+ * Added interface Serializeable
+ * Added [pg_field_type_oid](http://php.net/pg_field_type_oid)() PostgreSQL function
+ * Added zend_declare_property_...() and zend_update_property_...() API functions for bool, double and binary safe strings
+ * Added possibility to access INI variables from within .ini file
+ * Added variable $_SERVER['REQUEST_TIME'] containing request start time
+ * Added optional float parameter to [gettimeofday](http://php.net/gettimeofday)()
+ * Added [apache_reset_timeout](http://php.net/apache_reset_timeout)() Apache1 function
+ * Added [sqlite_fetch_column_types](http://php.net/sqlite_fetch_column_types)() 3rd argument for arrays
+ * Added optional offset parameter to [stream_get_contents](http://php.net/stream_get_contents)() and [file_get_contents](http://php.net/file_get_contents)()
+ * Added optional maxlen parameter to [file_get_contents](http://php.net/file_get_contents)()
+ * Added SAPI hook to get the current request time
+ * Added new functions:
+ * [array_diff_key](http://php.net/array_diff_key)()
+ * [array_diff_ukey](http://php.net/array_diff_ukey)()
+ * [array_intersect_key](http://php.net/array_intersect_key)()
+ * [array_intersect_ukey](http://php.net/array_intersect_ukey)()
+ * [array_product](http://php.net/array_product)()
+ * DomDocumentFragment::[appendXML](http://php.net/appendXML)()
+ * [fputcsv](http://php.net/fputcsv)()
+ * [htmlspecialchars_decode](http://php.net/htmlspecialchars_decode)()
+ * [inet_pton](http://php.net/inet_pton)()
+ * [inet_ntop](http://php.net/inet_ntop)()
+ * mysqli::client_info property
+ * [posix_access](http://php.net/posix_access)()
+ * [posix_mknod](http://php.net/posix_mknod)()
+ * SimpleXMLElement::XPathNamespace()
+ * [stream_context_get_default](http://php.net/stream_context_get_default)()
+ * [stream_socket_enable_crypto](http://php.net/stream_socket_enable_crypto)()
+ * [stream_wrapper_unregister](http://php.net/stream_wrapper_unregister)()
+ * [stream_wrapper_restore](http://php.net/stream_wrapper_restore)()
+ * [stream_filter_remove](http://php.net/stream_filter_remove)()
+ * [time_sleep_until](http://php.net/time_sleep_until)()
+ * Added DomDocument::$recover property for parsing not well-formed XML Documents
+ * Added Cursor support for MySQL 5.0.x in mysqli
+ * Added proxy support to ftp wrapper via http
+ * Added MDTM support to ftp_url_stat
+ * Added zlib stream filter support
+ * Added bz2 stream filter support
+ * Added max_redirects context option that specifies how many HTTP redirects to follow
+ * Added support of parameter=>value arrays to [xsl_xsltprocessor_set_parameter](http://php.net/xsl_xsltprocessor_set_parameter)()
--- /dev/null
+---
+title: Submitting a bug for PHP
+author: m6w6
+tags:
+- PHP
+---
+
+There will surely be the time where you find a bug in PHP, but prior
+submitting half hearted bug report make sure you've accomplished the following
+things:
+
+ * [search the bug tracker](http://bugs.php.net/search.php) if the bug has already been subbmitted
+ * put together a short and behaviour reproducing script
+ * verify the behaviour with the **latest** version AKA [snap](http://snaps.php.net) of PHP
+ * if PHP crashes, [generate a backtrace](http://bugs.php.net/bugs-generating-backtrace.php)
+
+If you're in doubt, read [this](http://bugs.php.net/how-to-report.php) if you
+didn't already (which you shouldn't tell anyone by the way).
+
--- /dev/null
+---
+title: Submitting a patch for PHP
+author: m6w6
+tags:
+- PHP
+---
+
+If you once have that odd feeling that something in PHP is missing and you're
+brave enough to write something up (a patch) that would change that situation
+in your eyes, don't expect such a submission will make it into old branches.
+
+Questions to include new features in PHP-4 or PHP-5.0 will most probably be
+declined (for a good reason), so the chance that the invested time is wasted
+time is rather high.
+
+If you still feel confident about your addition, write the patch against the
+CVS HEAD or at least 5.1 branch, but for PHP-5.1 which is
+[around the corner](../../2005-11-13/php-51-around-the-corner/)
+the probability for acceptance of new features has decreased a lot (or rather
+completely).
+
+On the other hand, if your patch is trying to fix a
+[bug](http://bugs.php.net), don't hesitate to provide a patch for **every
+single** CVS branch ;)
+
--- /dev/null
+---
+title: Time to say Good Bye
+author: m6w6
+tags:
+- PHP
+---
+
+Yeah, it may come suddenly, but it's time to say good bye to curly braces used
+as string indexing operator.
+
+PHP-5.1 will issue an E_STRICT error, and PHP-6 will probably don't know this
+syntax any more.
+
+I don't know why, but I've got some strange sentimental feelings :-) , maybe
+because I've never used those other brackets for string indexing...
+
+So, beloved, I already miss you! :'(
+
--- /dev/null
+---
+title: Boost your Website with APC
+author: m6w6
+tags:
+- PHP
+---
+
+Two weeks ago I plugged [APC](http://pecl.php.net/package/APC) onto my main
+customers site, and I'm really satisfied by it now. I already tried it some
+time ago, but back then it had some problems with PEARs Quickforms and
+similiar heavy OO code, but those problems are fixed for about 90% now, some
+8% can be easily fixed by reordering **require** statements and the like and
+finally the remaining ~2% are going to be fixed by Rasmus in the foreseeable
+future.
+
+Note that I'm using APC with Debians PHP-4.3.10 and Apache2 package, which
+proofs a lot IMO ;) and there shouldn't be much that hinders you from trying
+it too!
+
+Here's a very simple instruction to boost your PHP enabled webserver:
+```shell
+~$ pear download pecl/apc
+~$ tar xzf APC-3.0.8.tgz
+~$ rm -f package.xml
+~$ cd APC-3.0.8
+~/APC-3.0.8$ /usr/bin/phpize
+~/APC-3.0.8$ ./configure --with-php-config=/usr/bin/php-config
+ --enable-apc --enable-apc-mmap
+~/APC-3.0.8$ make all
+~/APC-3.0.8$ sudo make install
+```
+
+APC is now installed somewhere in /usr/lib/php.
+
+Some lines to add to php.ini:
+```ini
+extension=apc.so
+
+[apc]
+apc.enabled = 1
+apc.cache_by_default = 1
+apc.shm_size = 32
+apc.num_files_hint = 500
+apc.mmap_file_mask = /tmp/apc.XXXXXX
+```
+
+If you want to cache only a certain virtual host, set apc.cache_by_default to
+0 in php.ini and add the respective php_admin_value to your `<VirtualHost>`
+directive for the vhost.
+
+The package also contains a useful status script, just copy the shipped
+apc.php to your document root. You'll see how the usage of the SHM segment
+grows by time, and after some time you'll also see what settings to use for
+apc.num_files_hint and apc.shm_size when the whole site is cached.
+
+Sean recently added some [APC docs](http://docs.php.net/apc), too!
+
+Quod est demonstrandum, Website boosted! ;)
--- /dev/null
+---
+title: Hash Extension
+author: m6w6
+tags:
+- PHP
+---
+
+If you didn't notice yet, there's a new, seemingly unimpressive, nevertheless
+very useful, extension on the horizon, namely
+ext/[hash](http://pecl.php.net/package/hash).
+
+The initial version, proposed by Sara and Stefan -and it seems that Rasmus had
+his hands on it too- already featured the most common algorithms, and it has
+recently been extended to support now fairly every algo which libmhash
+provides.
+
+There's not been any public release yet, which means you'd need to build from
+CVS. [pecl4win](http://pecl4win.php.net) though, already provides fresh
+modules for Windows users.
+
+### It's usage is simple and intuitive
+Hashing a string:
+```php
+echo hash('sha384', 'The quick brown fox jumps over the lazy dog');
+```
+Hashing a file:
+```php
+echo hash_file('md5', 'release-1.0.tgz');
+```
+There's also an incremental interface available.
+
+The recently released version of the [HTTP
+extension](http://pecl.php.net/package/pecl_http) now uses the HASH extension
+instead of libmhash for generating its etag hashes.
+
+## Update:
+Just in case you missed, Sara released
+[pecl/hash](http://pecl.php.net/package/hash) today.
+Check it out -- It'll be bundled with PHP-5.1.2!
+
--- /dev/null
+---
+title: PECL::HTTP - A nasty bug and a new example
+author: m6w6
+tags:
+- PHP
+---
+
+I just fixed a nasty bug which caused GZIP encoded files (speak tgz etc.) to
+be decoded. While it'll just eat **some** memory on a 200 response (besides
+that the body is not what one would expect), it'll eat all memory on 206
+(partial content) responses because the part is fed through zlib. I'll just
+need to revisit the HTTP RFC to check if checking for the "Vary" response
+header is the best bet before I drop the new release.
+
+Ok, that's it about the bad news -- I also added a new example to the tutorial
+which shows how one could efficiently download big files. Using the example
+code would look like:
+
+```php
+$bigget = BigGet::url('http://example.com/big_file.bin');
+$bigGet->saveTo('big_file.bin');
+
+class BigGetRequest extends HttpRequest
+{
+ public $id;
+}
+
+class BigGet extends HttpRequestPool
+{
+ const SIZE = 1048576;
+
+ private $url;
+ private $size;
+ private $count = 0;
+ private $files = array();
+
+ static function url($url)
+ {
+ $head = new HttpRequest($url, HttpRequest::METH_HEAD);
+ $headers = $head->send()->getHeaders();
+ $head = null;
+
+ if (!isset($headers['Accept-Ranges'])) {
+ throw new HttpExcpetion("Did not receive an ".
+ "Accept-Ranges header from HEAD $url");
+ }
+ if (!isset($headers['Content-Length'])) {
+ throw new HttpException("Did not receive a ".
+ "Content-Length header from HEAD $url");
+ }
+
+ $bigget = new Bigget;
+ $bigget->url = $url;
+ $bigget->size = $headers['Content-Length'];
+ return $bigget;
+ }
+
+ function saveTo($file)
+ {
+ $this->send();
+ if ($w = fopen($file, 'wb')) {
+ echo "nCopying temp files to $file ...n";
+ foreach (glob("bigget_????.tmp") as $tmp) {
+ echo "t$tmpn";
+ if ($r = fopen($tmp, 'rb')) {
+ stream_copy_to_stream($r, $w);
+ fclose($r);
+ }
+ unlink($tmp);
+ }
+ fclose($w);
+ echo "nDone.n";
+ }
+ }
+
+ function send()
+ {
+ // use max 3 simultanous requests with a req size of 1MiB
+ while ($this->count < 3 &&
+ -1 != $offset = $this->getRangeOffset()) {
+ $this->attachNew($offset);
+ }
+
+ while ($this->socketPerform()) {
+ if (!$this->socketSelect()) {
+ throw new HttpSocketException;
+ }
+ }
+ }
+
+ private function attachNew($offset)
+ {
+ $stop = min($this->count * self::SIZE + self::SIZE,
+ $this->size) - 1;
+
+ echo "Attaching new request to get range: $offset-$stopn";
+
+ $req = new BigGetRequest(
+ $this->url,
+ HttpRequest::METH_GET,
+ array(
+ 'headers' => array(
+ 'Range' => "bytes=$offset-$stop"
+ )
+ )
+ );
+ $this->attach($req);
+ $req->id = $this->count++;
+ }
+
+ private function getRangeOffset()
+ {
+ return ($this->size >=
+ $start = $this->count * self::SIZE) ? $start : -1;
+ }
+
+ protected function socketPerform()
+ {
+ try {
+ $rc = parent::socketPerform();
+ } catch (HttpRequestPoolException $x) {
+ foreach ($x->exceptionStack as $e) {
+ echo $e->getMessage(), "n";
+ }
+ }
+
+ foreach ($this->getFinishedRequests() as $r) {
+ $this->detach($r);
+
+ if (206 != $rc = $r->getResponseCode()) {
+ throw new HttpException(
+ "Unexpected response code: $rc");
+ }
+
+ file_put_contents(
+ sprintf("bigget_%04d.tmp", $r->id),
+ $r->getResponseBody());
+
+ if (-1 != $offset = $this->getRangeOffset()) {
+ $this->attachNew($offset);
+ }
+ }
+
+ return $rc;
+ }
+}
+```
--- /dev/null
+---
+title: PECL::HTTP 0.20.0 outta door
+author: m6w6
+tags:
+- PHP
+---
+
+Version 0.20.0 of [pecl/http](http://pecl.php.net/package/pecl_http) has been
+released!
+This is considered the most stable and friggin best release so far ;) so
+you're really encouraged to upgrade.
+
+### Release notes follow:
+
+* Request functionality requires libcurl >= 7.12.3 now
++ Added 'bodyonly' request option
++ Added IOCTL callback for cURL
++ Added ssl_engines array and cookies array to the request info array
++ Added http_parse_cookie() to parse Set-Cookie headers
+- Renamed http_connectcode to connect_code in the request info array
+- Enable "original headers" previously stripped off by the
+ message parser:
+ o X-Original-Transfer-Encoding (Transfer-Encoding)
+ o X-Original-Content-Encoding (Content-Encoding)
+ o X-Original-Content-Length (Content-Length)
+- RequestExceptions thrown by HttpRequestPool::__construct() and
+ send() are now wrapped into the HttpRequestPoolException
+ object's $exceptionStack property
+- Removed http_compress() and http_uncompress()
+ (http_deflate/inflate ambiguity)
+* Fixed bug which caused GZIP encoded archives to be decoded
+* Fixed bug with DEFLATE encoded response messages
+* Fixed several memory leaks and inconspicuous access violations
+* Fixed some logical errors in the uri builder
+
--- /dev/null
+---
+title: s/fluent/decorated/
+author: m6w6
+tags:
+- PHP
+---
+
+I've [read](http://www.achievo.org/blog/archives/25-The-danger-of-Fluent-interfaces.html)
+[some](http://andigutmans.blogspot.com/2005/12/fluent-interfaces.html)
+[posts](http://paul-m-jones.com/blog/?p=188) about "fluent interfaces" and
+I have to agree that it's a bad idea to sacrifice a reasonable
+API to be able to write english code.
+
+It's anyway possible to accomplish that to some extent on a need-by-need basis
+with a class of only 20 lines of code:
+
+```php
+class ReturnThisDecorator
+{
+ private $object;
+ public $result;
+
+ function __construct($object)
+ {
+ if (is_object($object)) {
+ $this->object = $object;
+ } else {
+ throw new InvalidArgumentException(
+ "Expected an object as argument"
+ );
+ }
+ }
+
+ function __call($method, $params)
+ {
+ $this->result = call_user_func_array(
+ array($this->object, $method), $params
+ );
+ return $this;
+ }
+}
+
+$sms = new ReturnThisDecorator(new SMS);
+echo $sms->from('...')->to('...')->message('...')->send()->result;
+```
--- /dev/null
+---
+title: Apache2 mod_domaintree version 1.3
+author: m6w6
+tags:
+- PHP
+- WEB
+---
+
+I just released
+[mod_domaintree](http://freshmeat.net/projects/mod_domaintree/)-1.3 on
+[freshmeat](http://freahmeat.net).
+
+It'll take some time to appear, though.
+
+The code has been cleaned up a lot and a host name to directory cache (per
+server/process) has been added.
+
+Enable the cache by setting DomainTreeCache to a reasonable high number, like
+the amount of different domains being hosted.
+
+Drop me a [mail](mailto:mike@iworks.at) if you like it! ;)
+
--- /dev/null
+---
+title: imap_savebody()
+author: m6w6
+tags:
+- PHP
+---
+
+If you -like me- were suffering from being unable to load big attachments
+through ext/imap because of PHPs memory limit, the new imap_savebody()
+function should be what you were looking for. It adds the ability to save any
+section (full mail, too) of a mail message to a file or stream.
+
+Adding it implied a non-trivial change to ext/imap, so if you encounter any
+new problems -with f.e. imap_fetchbody()- speak up ASAP, please! ;)
--- /dev/null
+---
+title: Some cool new features of pecl/http
+author: m6w6
+tags:
+- PHP
+---
+
+[PECL::HTTP](http://pecl.php.net/package/pecl_http) version 0.22 has been
+released this morning, and I want to point at some features which have been
+added to the extension since I last blogged about it.
+
+Incremental zlib (de)compressors were added in form of two classes,
+[HttpDeflateStream](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpDeflateStream) and
+[HttpInflateStream](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpInflateStream). I hope the names say it all ;)
+
+Another class, that might seem a bit odd at a quick glance, is
+[HttpQueryString](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpQueryString). It's a great tool to realize "paging" or
+sites with lots of rewrite rules AKA "pretty urls".
+
+The class [HttpMessage](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpMessage) has finally got its iterator interface to move
+up the message chain in a more convenient way. Messages can now be
+[detached](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpMessage_detach) and
+[prepended](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpMessage_prepend) from/to the message chain.
+
+Thanks to [Ilia](http://ilia.ws) you can now retrieve the raw request and
+response messages sent resp. received by an
+[HttpRequest](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpRequest) instance.
+
+The function [http_build_url](http://dev.iworks.at/ext-http/http-functions.html.gz#http_build_url) is now the most versatile and powerful
+utility to handle URLs (sorry for the lack of docs). Please [tell
+me](mailto:mike@iworks.at) if you don't think so ;)
+
--- /dev/null
+---
+title: pecl/http update
+author: m6w6
+tags:
+- PHP
+---
+
+Yeah, you guessed, version 0.23 of
+[pecl/http](http://pecl.php.net/package/pecl_http) has been released, and it's
+time for a feature update ;)
+
+### Cookies
+
+[http_parse_cookie](http://dev.iworks.at/ext-http/http-functions.html.gz#http_parse_cookie)() has been reimplemented (and
+HttpRequest::getResponseCookie() has been moved to
+[HttpRequest::getResponseCookies](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpRequest_getResponseCookies)().
+After revisiting the
+original Netscape [draft](http://wp.netscape.com/newsref/std/cookie_spec.html)
+and the two [cookie](ftp://ftp.rfc-editor.org/in-notes/rfc2109.txt)
+[RFCs](ftp://ftp.rfc-editor.org/in-notes/rfc2965.txt) it was pretty obvious
+that the previous implementation was pretty bogus.
+
+Now it works as follows:
+
+```php
+http_parse_cookie("cookie1=value; cookie2=\"1;2;3;4\"; path=/");
+/*
+stdClass Object
+(
+ [cookies] => Array
+ (
+ [cookie1] => value
+ [cookie2] => 1;2;3;4
+ )
+
+ [extras] => Array
+ (
+ )
+
+ [flags] => 0
+ [expires] => 0
+ [path] => /
+ [domain] =>
+)
+*/
+```
+
+As you can see, a cookie line can have several name/value pairs. The standard
+additional fields like expires, path etc. are recogniced automatically. The
+RFCs, though, define some other standard extra elements, here's where the
+third parameter of http_parse_cookie() plays in:
+
+```php
+http_parse_cookie("cookie1=value; cookie2=\"1;2;3;4\"; comment=\"none\"; path=/",
+ 0, array("comment"));
+/*
+stdClass Object
+(
+ [cookies] => Array
+ (
+ [cookie1] => value
+ [cookie2] => 1;2;3;4
+ )
+
+ [extras] => Array
+ (
+ [comment] => none
+ )
+
+ [flags] => 0
+ [expires] => 0
+ [path] => /
+ [domain] =>
+)
+*/
+```
+
+If "comment" wouldn't have been specified as an allowed extra element, it
+would just have been recognized as another cookie.
+IF you pass HTTP_COOKIE_PARSE_RAW as second parameter to http_parse_cookie(),
+no urldecoding is performed.
+The flags in the return value is a bitmask of HTTP_COOKIE_SECURE and
+HTTP_COOKIE_HTTPONLY.
+
+### Messages
+
+Some users pointed me to the fact that neither
+[HttpMessage](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpMessage)
+nor [HttpRequest](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpRequest)
+provide accessors to the HTTP
+response reason phrase AKA status text. They've been added in form of
+[HttpMessage::getResponseStatus](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpMessage_getResponseStatus)() and
+[HttpRequest::getResponseStatus](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpRequest_getResponseStatus)().
+
+Some might have wondered why [HttpMessage](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpMessage)s are
+chained in kind of a reverse order. Well, that has internal reasons, caused by how we retreive the data from
+[libcurl](http://curl.haxx.se) and how the message parser works. Anyway
+there's now [HttpMessage::reverse](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpMessage_reverse)()
+which reorders the messages in a more intuitive chronical way:
+
+```php
+$msg = new HttpMessage(
+"GET / HTTP/1.1
+HTTP/1.1 302 Found
+Location: /foo
+GET /foo HTTP/1.1
+HTTP/1.1 200 Ok");
+foreach ($msg as $m) echo $m;
+foreach ($msg->reverse() as $m) echo $m;
+/*
+HTTP/1.1 200 Ok
+GET /foo HTTP/1.1
+HTTP/1.1 302 Found
+Location: /foo
+GET / HTTP/1.1
+
+GET / HTTP/1.1
+HTTP/1.1 302 Found
+Location: /foo
+GET /foo HTTP/1.1
+HTTP/1.1 200 Ok
+*/
+```
+
+Note, though, that [HttpMessage::toString](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpMessage_toString)(true) automatically prepends parent
+messages, i.e. gives the latter result.
+
+### Requests
+
+For servers that don't urldecode cookies, a new option has been added, named
+"encodecookies", which omits urlencoding cookies if set to FALSE.
+
+Similarily to the "lastmodified" request option, there's now an "etag" option
+working along the same lines.
+
+[HttpRequest::getHistory](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpRequest_getHistory)()
+now returns a real HttpMessage property, which measn that this message chain is no longer immutable to
+changes made by the user.
+
+If a request fails for some reason, you should now be able to get the error
+message through [HttpRequest::getResponseInfo](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpRequest_getResponseInfo)("error").
+
--- /dev/null
+---
+title: End of Youth
+author: m6w6
+tags:
+- PHP
+---
+
+After more than a year of development and bulldozing the pecl-cvs mailing
+list, I'm ready to move [pecl/http](http://pecl.php.net/package/pecl_http)
+into 1.0-RC stage.
+
+Version 0.25 has just been released and I'm confident that we'll see a stable
+1.0 release not later than April.
+
+Thanks for your condolescence and patience in the last few months :)
+
--- /dev/null
+---
+title: Cookie Handling
+author: m6w6
+tags:
+- PHP
+---
+
+I noticed some _weirdance_ about how libcurl and thus pecl/http handles
+cookies.
+
+I had to implement some changes which are only in CVS for now and which I'm
+going to outline here:
+
+```php
+$r = new HttpRequest("http://www.google.at/");
+$r->recordHistory = true;
+// we don't care about cookies by default
+// enable automatic recognition of cookies
+$r->enableCookies();
+$r->send();
+// received cookies will be sent on the next request
+$r->send();
+// reset those "auto" cookies
+// this needs at least libcurl >= v7.14.1
+$r->resetCookies();
+$r->send();
+echo $r->getHistory()->toString(true);
+```
+
+Beware that all this does not affect custom cookies set with
+[HttpRequest::setCookies](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpRequest_setCookies)() and
+[HttpRequest::addCookies](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpRequest_addCookies)().
+Custom cookies can always be unset by calling HttpRequest::setCookies().
+
+A final note on using the **cookiestore** option:
+
+```php
+$r = new HttpRequest("http://www.google.at/");
+// load and save cookies from /tmp/cookies.txt
+// if 'cookiesession' is TRUE, session cookies
+// won't be loaded from the cookiestore
+$r->setOptions(array(
+ "cookiesession" => TRUE,
+ "cookiestore" => "/tmp/cookies.txt")
+);
+$r->send();
+```
+
+Note that using the cookiestore automatically enables libcurls cookie engine.
+
--- /dev/null
+---
+title: Konquerors ViewMode Buttons
+author: m6w6
+tags:
+- WTF
+---
+
+If you, after upgrading to Dapper Drake, are missing your beloved ViewMode
+Buttons in Konqueror, locate
+`/usr/share/kubuntu-default-settings/kde-profile/default/share/apps/konqueror/konq-kubuntu.rc`
+and add the following ToolBar node:
+```xml
+<ToolBar newline="false" hidden="false" name="viewModeToolBar" >
+ <text>ViewMode Toolbar</text>
+ <ActionList name="viewmode_toolbar" />
+</ToolBar>
+```
+
+Yes, you guessed, this drove me mad ;)
--- /dev/null
+---
+title: Finally
+author: m6w6
+tags:
+- PHP
+---
+
+I finally managed to release [pecl/http version 1.0.0](http://pecl.php.net/package/pecl_http/1.0.0).
+
+Happy HTTPing! ;)
+
--- /dev/null
+---
+title: Installing pecl_http
+author: m6w6
+tags:
+- PHP
+---
+
+As [pecl/http](http://pecl.php.net/package/pecl_http) 1.0 has finally been
+released and I had noticed that it's been packaged already by several projects
+like PLD, Gentoo and FreeBSD, I wanted to explain what one is going to gain
+respectively lose by using the different build/configure options for the
+extension.
+
+The help text of configure for pecl/http should look similar to the following:
+```
+ --enable-http Enable extended HTTP support
+ --with-http-curl-requests[=LIBCURLDIR]
+ HTTP: with cURL request support
+ --with-http-zlib-compression[=LIBZDIR]
+ HTTP: with zlib encodings support
+ --with-http-magic-mime[=LIBMAGICDIR]
+ HTTP: with magic mime response content type guessing
+ --with-http-shared-deps HTTP: disable to not depend on extensions like hash,
+ iconv and session (when built shared)
+```
+
+If you link the extension source directory into your php tree, you should be
+aware that these options show up on the end of the list of configure options
+for **extensions** , not--as probably expected--in alphabetical order. This is
+due to a recent change to use config9.m4 because the HTTP extension may depend
+on several other PHP extensions ([hash](http://php.net/hash),
+[iconv](http://php.net/iconv), [session](http://php.net/session)).
+
+
+--with-http-curl-requests
+: This configure option enables request functionality, uses
+[libcurl](http://curl.haxx.se/libcurl/) and is _highly recommended_ to be
+enabled. The minumum libcurl version required is 7.12.3. Debian/stable
+currently ships 7.13.2 (no, this is not a typo).
+
+--with-http-zlib-compression
+: I think this is the most overseen/ignored option. Besides handling of
+compressed HTTP messages, it also provides superior deflate/inflate
+functionaly in regards to stability and performance compared to the standard
+zlib extension. Both [http_deflate](http://dev.iworks.at/ext-http/http-functions.html.gz#http_deflate)()
+/[http_inflate](http://dev.iworks.at/ext-http/http-functions.html.gz#http_inflate)() functions and
+http.deflate/http.inflate stream filters are able to encode/decode all valid
+gzip, zlib (AKA deflate) and raw deflated data. It requires at lieast libz
+version 1.2.0.4, while Debian/stable ships 1.2.2, and is also _highly recommended_ to be enabled.
+
+
+
+--with-http-magic-mime
+: This option enables content type guessing for the
+[HttpResponse](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpResponse)
+and [HttpMessage](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpMessage)
+classes. It's rather a gimmick and
+thus not enabled by default. As there's no version information available for
+libmagic, I don't even know which is the minimum version required but I guess
+anything coming from a file-4.1x versioned package should work. If you get an
+empty string as content type for payload which is obviously XML text, check
+the magic.mime database you use for a broken **first** XML section. Comment
+out everything except the SVG detection as other XML types and HTML is handled
+further down the magic file (noticed on Debian systems). If you changed your
+magic.mime database, don't forget to regenerate the precompiled version with
+the `file -C` command.
+
+
+
+--with-http-shared-deps
+: This option controls whether pecl/http will depend on extensions built as
+dynamically loadable modules. So, if e.g. ext/iconv has been compiled shared,
+pecl/http relies on ext/iconv to be loaded when itself is going to be loaded.
+This option is enabled by default.
+
+ * _ext/hash_
+ pecl/http uses ext/hash to generate ETag hashes (else standard PHP MD5, SHA1 or CRC32).
+ * _ext/iconv_
+ If ext/iconv is present, the [HttpQueryString](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpQueryString)
+ class provides an [xlate](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpQueryString_xlate)() method for charset transformation.
+ * _ext/session_
+ [http_redirect](http://dev.iworks.at/ext-http/http-functions.html.gz#http_redirect)() can
+ automatically append session information to the redirect URL.
+ * _ext/spl_
+ ext/spl cannot be built shared, so pecl/http always uses it if it's enabled.
+ [HttpMessage](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpMessage) and
+ [HttpRequestPool](http://dev.iworks.at/ext-http/http-functions.html.gz#HttpRequestPool)
+ classes implement the interface Countable provided by ext/spl.
+
--- /dev/null
+---
+title: Round up
+author: m6w6
+tags:
+- PHP
+---
+
+It's been a long time since I wrote something here, mostly because I got
+distracted by some real private life recently ;) and due to paid work of
+course. Therefore I thought I'd round up what has happened behind the scenes
+in my PHP world.
+
+## PHP-6
+I rewrote the output control layer for PHP-6 some months ago and I'm about to
+upgrade ext/zlib to see how it really works out.
+
+## PHP-5.2
+I didn't contribute that much to this upcoming release. Two things I'd like to
+mention are a fix for the Apache2 SAPI where each header("Content-Type:
+aaa/bbb") caused Apache to add output filters for the type to the outgoing
+filter chain and the addition of the error_get_last() function, which is a
+convenient accessor to the last occured error without fiddling around with
+INI(track_errors) and $php_errormsg.
+
+
+## pecl/http
+There's official [documentation](http://php.net/http) now available online in
+the PHP manual, yay! :) It's not fully fleshed out, but gives some feeling
+about the provided functionality and hints on how to use this module.
+
+[php|a](http://www.phparch.com/) published an article by me about pecl/http in
+their Augusts issue!
+
+There have also been three releases since 1.0, the most recent one (1.2)
+today. See the changes since then outlined below.
+
+### Improvements/Additions
+
+ * Improved response performance (HttpResponse, http_send API)
+ * Added http_build_cookie() function
+ * Added HttpQueryString::mod(array $params) method
+ * Added ArrayAccess to interfaces implemented by HttpQueryString
+ * Added HttpMessage::getHeader(string $name) method
+
+### Bug Fixes
+
+ * Fixed http_parse_cookie() allowed_extras and flags parameters
+ * Fixed configuration with shared dependencies
+ * Fixed endless loop in http_build_url("..")
+ * Fixed HttpResponse::capture() failure if buffered output exceeds 40k
+ * Fixed HttpQueryString failures with objects as params
+ * Fixed memory leaks with overloaded classes extending HTTP classes
+ * Fixed build with gcc-2.95 (Thanks to Alexander Zhuravlev)
+ * Fixed memory leak in inflate code (Thanks to Thomas Landro Johnsen)
+
--- /dev/null
+---
+title: __get() and array rumors
+author: m6w6
+tags:
+- PHP
+---
+
+There've been lots of rumors about overloaded array properties lately.
+
+The following code
+```php
+class funky {
+ private $p = array();
+ function __get($p) {
+ return $this->p;
+ }
+}
+$o = new funky;
+$o->prop["key"] = 1;
+```
+
+will yield:
+
+```shell
+Notice: Indirect modification of overloaded property funky::$p has no effect
+```
+
+As arrays are the only complex types that are passed by value (resources don't
+really count here) the solution to described problem is simple: use an object;
+either an instance of stdClass or ArrayObject will do well, depending if you
+want to use array index notation.
+
+So the folloiwng code will work as expected, because the ArrayObject instance
+will pe passed by handle:
+
+```php
+class smarty {
+ private $p;
+ function __construct() {
+ $this->p = new ArrayObject;
+ }
+ function __get($p) {
+ return $this->p;
+ }
+}
+$o = new smarty;
+$o->prop["key"] = 1;
+```
+
+I guess most of you already knew, but anyway... ;)
+
--- /dev/null
+---
+title: HttpRequestDataShare
+author: m6w6
+tags:
+- PHP
+---
+
+There are some news to talk about development of
+[pecl/http](http://pecl.php.net/package/pecl_http).
+
+I recently implemented an interface to the [curl-
+share](http://curl.haxx.se/libcurl/c/libcurl-share.html) functionality in form
+of an HttpRequestDataShare class.
+
+This is what [reflection](http://php.net/reflection) will tell you about it:
+
+```shell
+mike@honeybadger:~/build/php-5.2-debug$ cli --rc HttpRequestDataShare
+Class [ <internal:http> class HttpRequestDataShare implements Countable ] {
+
+ - Constants [0] {
+ }
+
+ - Static properties [1] {
+ Property [ private static $instance ]
+ }
+
+ - Static methods [1] {
+ Method [ <internal> static public method singleton ] {
+
+ - Parameters [1] {
+ Parameter #0 [ <optional> $global ]
+ }
+ }
+ }
+
+ - Properties [4] {
+ Property [ <default> public $cookie ]
+ Property [ <default> public $dns ]
+ Property [ <default> public $ssl ]
+ Property [ <default> public $connect ]
+ }
+
+ - Methods [5] {
+ Method [ <internal, dtor> public method __destruct ] {
+
+ - Parameters [0] {
+ }
+ }
+
+ Method [ <internal, prototype Countable> public method count ] {
+
+ - Parameters [0] {
+ }
+ }
+
+ Method [ <internal> public method attach ] {
+
+ - Parameters [1] {
+ Parameter #0 [ <required> HttpRequest $request ]
+ }
+ }
+
+ Method [ <internal> public method detach ] {
+
+ - Parameters [1] {
+ Parameter #0 [ <required> HttpRequest $request ]
+ }
+ }
+
+ Method [ <internal> public method reset ] {
+
+ - Parameters [0] {
+ }
+ }
+ }
+}
+```
+
+Using this class, you can save a fair amount of time with name lookups which
+the following example shows:
+```php
+$s = HttpRequestDataShare::singleton(true);
+print_r($s);
+for ($i = 0; $i < 10; ++$i) {
+ $r = new HttpRequest("http://www.google.com/");
+ $s->attach($r);
+ $r->send();
+ printf("%0.6fn", $r->getResponseInfo("namelookup_time"));
+ $s->detach($r);
+}
+```
+
+Executing this script without dns data sharing enabled gives the following
+results:
+```shell
+mike@honeybadger:~/build/php-5.2-debug$ cli -d"http.request.datashare.dns=0"
+ ~/devel/http_rshare.php
+HttpRequestDataShare Object
+(
+ [cookie] =>
+ [dns] =>
+ [ssl] =>
+ [connect] =>
+)
+0.071296
+0.048798
+0.049598
+0.051545
+0.046258
+0.052318
+0.043769
+0.060753
+0.049168
+0.048568
+```
+
+...and with dns data sharing enabled:
+```shell
+mike@honeybadger:~/build/php-5.2-debug$ cli -d"http.request.datashare.dns=1"
+ ~/devel/http_rshare.php
+HttpRequestDataShare Object
+(
+ [cookie] =>
+ [dns] => 1
+ [ssl] =>
+ [connect] =>
+)
+0.051945
+0.000043
+0.000041
+0.000040
+0.000039
+0.000041
+0.000041
+0.000040
+0.000040
+0.000041
+```
+
+ **QED**
+
+You can either use a per-process global datashare object created with
+HttpRequestDataShare::singleton(true) or different instances for your
+HttpRequest objects. Note that dns datasharing is used autmagically for
+HttpRequestPool requests. Currently libcurl has implemented cookie and dns
+data sharing only, trying to enable ssl session or connect sharing will raise
+a warning.
+
+Be sure to try it out; either directly from CVS or the next release, probably
+being 1.3.0RC1.
--- /dev/null
+---
+title: HTTP, CURL and stuff
+author: m6w6
+tags:
+- PHP
+---
+
+News, news, yawn.
+
+Daniel Stenberg, head of the [cURL](http://curl.haxx.se) project,
+[accepted](http://permalink.gmane.org/gmane.comp.web.curl.library/13439) a
+patch for sub second time out support within libcurl. That means that you can
+use float values as time outs with a millisecond resolution, as soon as you
+use libcurl >= v7.16.2, that is, a minimum supported time out of 0.001 seconds
+(which is **not** reasonable, just in case you wonder). On a side note, you
+should build libcurl with [c-ares](http://daniel.haxx.se/projects/c-ares/) to
+get working sub second DNS lookup time out support, AFAICT.
+
+Clay Loveless, usually [killing people softly with his random strings](http://killersoft.com/randomstrings/),
+[mashing up APIs](http://mashery.com) or [providing compatibility libraries](http://code.google.com/p/phttp/),
+kindly asked me, if there were persistent connection support in
+[pecl/http](http://pecl.php.net/package/pecl_http).
+
+> _Is there an option in pecl_http that I'm overlooking that would be the
+equivalent of STREAM_CLIENT_PERSISTENT?_
+
+I was already about to answer that libcurl already does that all for us,
+realizing that we destroy the used CURL handles at the end of each PHP request
+at the latest, thus killing any alive connections. This happened about two
+weeks ago, and pecl/http 1.5, of which RC1 had just been released, will
+support per process persistent CURL handles. It can be enabled at compile time
+only, as it's a quite intrusive feature. Yet I'm still unsure about the
+implementation of this feature and it might change in the future to become a
+bit more user-friendly.
+
+To use it, there's nothing else to be done than tossing --enable-http-
+persistent-handles at configure.
+
--- /dev/null
+---
+title: Something I didn't even know I was missing
+author: m6w6
+tags:
+- PHP
+---
+```shell
+$ php --ri extension
+```
+
+Nice.
+
--- /dev/null
+---
+title: Upgrading to 5.2
+author: m6w6
+tags:
+- PHP
+---
+
+So I finally came around to upgrade to PHP 5.2 (I was running 4.4 on the
+production server until now). I know, what a shame! :)
+
+Anyway the only issue I really had, in spite testing the code really well over
+time, was with class_exists() and millions of warnings becaus of a missing
+__autoload(). I blame the people who introduced the second parameter to
+class_exists() **and** changing the default behaviour at the very same moment.
+Actually, it was an annoying but rather easy to fix compatibility brake.
+
+APC in conjunction with PHP-5.2 seems to work very well either, it even feels
+a lot less memory exhaustive than running APC+PHP-4.
+
+Ah yes, just on a side note, I also upgraded to Apache-2.2 in the same run.
+Somehow I now have a warm and fuzzy feeling running this up-to-date software,
+it really was already like a brinck in my stomach. Anyway, what's left is to
+migrate from the Apache module to the FastCGI SAPI and switching to the worker
+MPM... but I'm done already.
+
--- /dev/null
+---
+title: Apache MultiViews are evil
+author: m6w6
+tags:
+- WTF
+- WEB
+---
+
+Suppose you've got a similar setup to:
+
+```apache
+RewriteEngine On
+RewriteBase /
+
+RewriteCond %{REQUEST_FILENAME} -f [OR]
+RewriteCond %{REQUEST_FILENAME} -d
+RewriteRule .* - [QSA,L]
+
+RewriteRule ^network/?(w+)?$ network.php?path=$1
+```
+
+Apache will expand e.g. "network/foo/bar" to "network.php/foo/bar" which won't
+be expanded to "network.php?f=" because it --of course-- exists (RewriteCond -f).
+
+Evil! :)
+
--- /dev/null
+---
+title: Two pitfalls in one afternoon
+author: m6w6
+tags:
+- WTF
+- WEB
+---
+
+This is not my day.
+
+<quote url="<http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html>">
+
+> words that are present in more than 50% of the rows are considered common and do not match
+
+</quote>
+
+RTFM! ;)
+
--- /dev/null
+---
+title: Phar vs World
+author: m6w6
+tags:
+- WTF
+- PHP
+---
+
+Recent [discussions](http://marc.info/?t=117857313600047&r=1&w=2) about
+inclusion of [pecl/phar](http://pecl.php.net/package/phar) into the core
+distribution shows again that we are missing a defined process of handling
+additions to the PHP main distibution. How many people are really reading
+through all mails of 100+ message threads?
+
+It's going to be a chaos. Always. Once a developer has got his new, shiny and
+soon-to-be-world-dominating extension into the core, he'll be a even stronger
+advocator of the "no-new-extensions" camp. Not to disrespect any work, but
+this is pure rivalism, masculine--really!
+
+The idea of moving extensions from core to pecl is honorous, but we all know
+the current problems of this ideology.
+
+Many people have asked me when
+[pecl/http](http://pecl.php.net/package/pecl_http) will be included in the
+main distribution. My answer is short and simple: "Never" (I usually add a
+tiny sentence, but that's nothing encouraging either).
+
+Ah... and please do me a favour: rather keep your comments to yourself :)
+(...or toss it into the nonsense thread@internals).
+
--- /dev/null
+---
+title: Silence
+author: m6w6
+tags:
+- PHP
+---
+
+It's been [more than 3 months](http://blog.iworks.at/?/archives/50-HTTP,-CURL-and-stuff.html)
+that I brought back to mind, what was happening in my PHP/HTTP/CURL world, so here we go.
+
+#### February:
+
+[pecl/http](http://pecl.php.net/package/pecl_http) with support for persistent
+handles has been released.
+
+A [proposal of mine at internals](http://marc.info/?l=php-dev&m=117188035610011&w=2)
+to change the behaviour of read_property/write_property and get_property_ptr_ptr object handlers has
+successfully been ignored.
+
+The idea was the following:
+
+> Wouldn't it be reasonable for the engine to use get_property_ptr_ptr()
+whenever it wants to modify a property and get rid of using read_property()
+for write access?
+> That would make rather simple ops like concatenation, in-/decrementation etc
+work again with overloaded internal classes. Just make the engine use
+read_property() followed by a write_property() when there's no
+get_property_ptr_ptr().
+
+
+Nobody was interested.
+
+#### March:
+
+I [added a comparison object handler](http://cvs.php.net/viewvc.cgi/php-src/ext/date/php_date.c?r1=1.131&r2=1.132&diff_format=u)
+to the DateTime class, which means that comparisons of DateTime objects should work in recent
+PHP5 versions.
+
+I started development of pecl/libetpan, but [dropped it again](http://marc.info/?l=pecl-dev&m=117464452600994&w=2)
+because of pretty huge differences between how the library works and how PHP is supposed to
+work. What a pity.
+
+A less fine guy, some Omid, wanted me to write a PHP extension which
+calculates the strength of "poker hands", but he jumped off when I had done
+the algos.
+
+#### April:
+
+A fine guy, pretending his name was Andreas Weber, noticed that pecl/http's
+request method implementation was completely b0rked. Thanks to his report it
+was fixed in 1.5.3.
+
+All fame Lukas Smith, queried me about what might have changed with my new
+output layer implementation for PHP6, but I noticed too late that it's been
+for a conference talk he was preparing, so I feel like I didn't spend enough
+attention to his questions. Sorry Lukas.
+
+I started to implement [libcurl's](http://curl.haxx.se) new multi_socket AKA
+hiper API in conjunction with [libevent](http://monkey.org/~provos/libevent/),
+but stumbled across a few
+[problem](http://curl.haxx.se/mail/lib-2007-04/0308.html)s.
+
+#### May:
+
+My journey with libcurl's multi_socket API
+[continues](http://curl.haxx.se/mail/lib-2007-05/0125.html), which eventually
+causes the delay of a first pecl/http 1.6 release candidate.
+
+I [tried](http://dev.iworks.at) [Drupal](http://drupal.org) for the first
+time.
+
+***
+
+Well, that'd be it. If it reads like an extrusion of junk, it probably was. ;)
+
--- /dev/null
+---
+title: Introducing libcurls multi socket API
+author: m6w6
+tags:
+- PHP
+---
+
+So, finally a first beta of [pecl_http](http://pecl.php.net/package/pecl_http)
+1.6 has been released.
+
+This is the first version which supports [libcurl](http://curl.haxx.se/libcurl/)s
+[multi socketAPI](http://curl.haxx.se/libcurl/c/curl_multi_socket.html) introduced in 7.16
+through libevent.
+
+
+Here's a not very impressive comparison of the performance of the traditional
+multi API vs. the new multi socket API:
+```shell
+mike@honeybadger:~/build/php-5.2-debug$ cli
+ ~/cvs/pecl/http/scripts/bench_select_vs_event.php
+ -u http://honeybadger/empty.html
+
+> 1.134667s
+
+mike@honeybadger:~/build/php-5.2-debug$ cli
+ ~/cvs/pecl/http/scripts/bench_select_vs_event.php
+ -u http://honeybadger/empty.html
+
+> 1.151088s
+
+mike@honeybadger:~/build/php-5.2-debug$ cli
+ ~/cvs/pecl/http/scripts/bench_select_vs_event.php
+ -u http://honeybadger/empty.html
+
+> 1.131867s
+
+mike@honeybadger:~/build/php-5.2-debug$ cli
+ ~/cvs/pecl/http/scripts/bench_select_vs_event.php
+ -u http://honeybadger/empty.html -e
+
+> 0.993878s
+
+mike@honeybadger:~/build/php-5.2-debug$ cli
+ ~/cvs/pecl/http/scripts/bench_select_vs_event.php
+ -u http://honeybadger/empty.html -e
+
+> 0.998832s
+
+mike@honeybadger:~/build/php-5.2-debug$ cli
+ ~/cvs/pecl/http/scripts/bench_select_vs_event.php
+ -u http://honeybadger/empty.html -e
+
+> 0.997121s
+```
+
+Above empty.html is, well, empty. The following test requests a 100k file:
+```shell
+mike@honeybadger:~/build/php-5.2-debug$ cli
+ ~/cvs/pecl/http/scripts/bench_select_vs_event.php
+ -u http://honeybadger/100k.bin
+
+> 2.205190s
+
+mike@honeybadger:~/build/php-5.2-debug$ cli
+ ~/cvs/pecl/http/scripts/bench_select_vs_event.php
+ -u http://honeybadger/100k.bin
+
+> 2.210525s
+
+mike@honeybadger:~/build/php-5.2-debug$ cli
+ ~/cvs/pecl/http/scripts/bench_select_vs_event.php
+ -u http://honeybadger/100k.bin
+
+> 2.254281s
+
+mike@honeybadger:~/build/php-5.2-debug$ cli
+ ~/cvs/pecl/http/scripts/bench_select_vs_event.php
+ -u http://honeybadger/100k.bin -e
+
+> 2.007220s
+
+mike@honeybadger:~/build/php-5.2-debug$ cli
+ ~/cvs/pecl/http/scripts/bench_select_vs_event.php
+ -u http://honeybadger/100k.bin -e
+
+> 1.945564s
+
+mike@honeybadger:~/build/php-5.2-debug$ cli
+ ~/cvs/pecl/http/scripts/bench_select_vs_event.php
+ -u http://honeybadger/100k.bin -e
+
+> 1.969575s
+```
+
+So, apparently time savings are not huge, but noticable.
+
--- /dev/null
+---
+title: Qmail + SpamAssassin + selectivity
+author: m6w6
+tags:
+- SYS
+---
+
+Here's how my qmail-queue script looks like to selectively check messages with
+SpamAssassin for non-relay clients only:
+
+```sh
+#!/bin/sh
+(if [ -n "${RELAYCLIENT+1}" -o `id -u` != 64011 ];
+ then cat -;
+ else /usr/bin/spamc -x -U /var/run/spamd/spamd.sock;
+fi) | /usr/sbin/qmail-queue.orig
+```
+
+For the records.
--- /dev/null
+---
+title: Vpopmail and people reaching their maildir quota
+author: m6w6
+tags:
+- SYS
+---
+
+This tiny program lists all users of a domain with a maildir quota usage above
+90%.
+
+```c
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <pwd.h>
+#include <errno.h>
+
+#include <vpopmail.h>
+#include <vauth.h>
+
+int main(int argc, char **argv) {
+ struct vqpasswd *user;
+ char dir[1024];
+ uid_t uid;
+ gid_t gid;
+ int offset_counter = -1, sort = 1, usage;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <domain>n", argv[0]);
+ return EXIT_FAILURE;
+ }
+ if (vget_assign(argv[1], NULL, 0, &uid, &gid) == NULL) {
+ fprintf(stderr, "domain '%s' does not existn", argv[1]);
+ return EXIT_FAILURE;
+ }
+ if (setgid(gid) || setuid(uid)) {
+ fprintf(stderr, "could not setuid/setgid to %d:%dn", uid, gid);
+ return EXIT_FAILURE;
+ }
+
+ while (NULL != (user = vauth_getall(argv[1], !++offset_counter, sort))) {
+ if (strcmp(user->pw_shell, "NOQUOTA")) {
+ snprintf(dir, sizeof(dir), "%s/Maildir", user->pw_dir);
+ usage = vmaildir_readquota(dir,
+ format_maildirquota(user->pw_shell));
+
+ if (usage >= 90) {
+ printf("%s %s %dn", user->pw_name, user->pw_shell, usage);
+ }
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+```
+
--- /dev/null
+---
+title: pecl_http and sub-second timeouts
+author: m6w6
+tags:
+- PHP
+---
+
+Just a quick info, because I forget this again and again -- and it's not noted
+in the [documentation](http://php.net/manual/en/ref.http.php) yet either.
+
+Sub-second timeouts are supported by [libcurl](http://curl.haxx.se/libcurl/)
+and thus by [pecl_http](http://pecl.php.net/pecl_http) -- yes but only if
+libcurl is built with [(c-)ares](http://c-ares.haxx.se) support:
+
+<quote url="[curl_easy_setopt.html](http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTTIMEOUTMS)">
+
+> If libcurl is built to use the standard system name resolver, that portion
+of the transfer will still use full-second resolution for timeouts with a
+minimum timeout allowed of one second.
+
+</quote>
+
--- /dev/null
+---
+title: PHP commandline highlighter
+author: m6w6
+tags:
+- WTF
+- PHP
+---
+
+Just chewed up a command line highlighter for php code.
+It's hacky, but it fulfills my needs.
+
+```php
+class CHL {
+ protected $colors = array(
+ "start" => "0:0",
+ "stop" => "0:0",
+ "comment" => "33",
+ "default" => "30",
+ "html" => "32",
+ "keyword" => "34",
+ "string" => "31",
+ );
+ protected $encoding = "UTF-8";
+ protected $tabstops;
+ protected $colwidth;
+ private $formats;
+
+ public function __construct() {
+ if ($files = $this->setup()) {
+ foreach ($files as $file) {
+ $this->highlight(file_get_contents($file), $file);
+ }
+ } elseif ($this->select()) {
+ $this->highlight(file_get_contents("php://stdin"), "<STDIN>");
+ } else {
+ $this->usage();
+ }
+ }
+
+ public function __destruct() {
+ if ($this->tabstops) {
+ echo "\033[3g";
+ $this->tabstops = 8;
+ $this->tabstops();
+ }
+ }
+
+ protected function usage() {
+ printf("Usage:\n");
+ printf("\n");
+ printf(" %s [-e ENC] [-t TAB] [-f FILE, ...] [-c TOKEN=COLOR, ...]\n", basename($_SERVER["argv"][0]));
+ printf("\n");
+ printf(" -e ENC specify the character set of the highlighted code\n");
+ printf(" -t TAB specify the tab with\n");
+ printf(" -f FILE specify one or more files to highlight, STDIN if omitted\n");
+ printf(" -c TOKEN=COLOR specify the color code for the type of token\n");
+ printf(" possible tokens: %s\n", implode(", ",array_keys($this->colors)));
+ printf("\n");
+ exit;
+ }
+
+ protected function setup() {
+ $files = array();
+ foreach (getopt("c:e:f:t:h") as $key => $val) {
+ switch ($key) {
+ case "h":
+ $this->usage();
+ break;
+ case "c":
+ foreach ((array)$val as $col) {
+ list($type, $color) = explode("=", $col);
+ $this->colors[$type] = $color;
+ }
+ break;
+ case "e":
+ $this->encoding = current(array_reverse((array)$val));
+ break;
+ case "t":
+ if ($tabstops = (int) current(array_reverse((array)$val))) {
+ $this->tabstops = $tabstops;
+ }
+ break;
+ case "f":
+ $files = (array) $val;
+ break;
+ }
+ }
+
+ if (!$this->colwidth = getenv("COLUMNS")) {
+ if (preg_match("/columns (\d+)/", shell_exec("stty -a"), $m)) {
+ $this->colwidth = $m[1];
+ } else {
+ $this->colwidth = 80;
+ }
+ }
+
+ $this->tabstops && $this->tabstops();
+ ini_set("highlight.comment", "comment");
+ ini_set("highlight.default", "default");
+ ini_set("highlight.html", "html");
+ ini_set("highlight.keyword", "keyword");
+ ini_set("highlight.string", "string");
+ $this->formats = array(
+ // get rid of html
+ "/\R/" => "",
+ "/<br \/>/" => "\n",
+ "/<\/span>/" => "",
+ "/( ){4}/" => "\t",
+ "/ /" => " ",
+ // convert colors
+ "/<span style=\"color: comment\">/" => $this->color("comment"),
+ "/<span style=\"color: default\">/" => $this->color("default"),
+ "/<span style=\"color: html\">/" => $this->color("html"),
+ "/<span style=\"color: keyword\">/" => $this->color("keyword"),
+ "/<span style=\"color: string\">/" => $this->color("string"),
+ // fix colors before newline
+ #"/((\033\[\d+m)+)([[:punct:][:space:]]*)(\r?\n)/s" => "\$1\$3\$4\$1",
+ // start/stop
+ "/<code>/" => $this->color("start"),
+ "/<\/code>/" => $this->color("stop", "", PHP_EOL),
+ );
+ return $files;
+ }
+
+ protected function select() {
+ $r = $w = $e = array();
+ $r[] = STDIN;
+ if (stream_select($r, $w, $e, 0, 100) && $r[0]) {
+ return true;
+ }
+ return false;
+ }
+
+ protected function tabstops() {
+ $colw = $this->colwidth;
+ $tabs = str_repeat(" ", $this->tabstops) . "\033H";
+ $tabs = str_repeat($tabs, $colw/$this->tabstops);
+ echo $tabs . "\r";
+ }
+
+ protected function color($type, $prepend = "", $append = "") {
+ return $prepend . "\033[" . implode("m\033[", explode(":", $this->colors[$type])) . "m" . $append;
+ }
+
+ protected function highlight($code, $name) {
+ echo "## Syntax highlighted code of $name:\n";
+ echo html_entity_decode(
+ preg_replace(
+ array_keys($this->formats),
+ array_values($this->formats),
+ highlight_string($code, true)
+ ),
+ ENT_QUOTES,
+ $this->encoding
+ );
+ echo PHP_EOL;
+ }
+}
+```
+
+Cheers-
+
--- /dev/null
+---
+title: Looking for PHP Geeks in Austria
+author: m6w6
+tags:
+- PHP
+---
+
+You guessed. I'm desperately looking for decent PHP Coders in Vienna, Austria.
+
+The job posting (in german) can be found here:
+<http://www.inqnet.at/job09.html>
+
+Just ping me if you're interested in an face-to-face interview.
--- /dev/null
+---
+title: WebSockets Handshake non HTTP conforming?
+author: m6w6
+tags:
+- WTF
+- PHP
+- WEB
+---
+
+
+While skimming through the new [HTML5 WebSocket draft](http://dev.w3.org/html5/websockets/),
+I noticed the following exemplar HTTP message demonstrating the client message of a WebSocket handshake:
+
+```http
+GET /demo HTTP/1.1
+Host: example.com
+Connection: Upgrade
+Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
+Sec-WebSocket-Protocol: sample
+Upgrade: WebSocket
+Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
+Origin: http://example.com
+
+^n:ds[4U
+```
+
+To me this looks non conforming to the [HTTP
+spec](http://www.w3.org/Protocols/rfc2616/rfc2616.html) due to the lack of an
+indicator that the request contains a message body.
+
+Quoting [the 4th paragraph of section 4.3 of
+RFC2616](http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3):
+
+> The **presence of a message-body** in a request **is signaled** by the
+inclusion of a **Content-Length or Transfer-Encoding header** field in the
+request's message-headers. A message-body MUST NOT be included in a request if
+the specification of the request method (section 5.1.1) does not allow sending
+an entity-body in requests. A server SHOULD read and forward a message-body on
+any request; if the request method does not include defined semantics for an
+entity-body, then the message-body SHOULD be ignored when handling the
+request.
+
+Huh?
+
--- /dev/null
+---
+title: courier imap, authdaemond and vpopmails vchkpw
+author: m6w6
+tags:
+- WTF
+- SYS
+---
+
+A few years ago, it was possible to have courier-imap update the open-smtp
+relay file with it's authvchkpw module. This feature and thus imap-before-smtp
+disappeared with the introduction of courier-authdaemond because the vchkpw
+code of authdaemond does not have a chance to see the TCPREMOTEIP environment
+variable.
+
+I more or less lived with that, until a friend of mine got a new iphone...
+well yeah, one of those i-geeks, and that gadget apparently only supports
+imap, no pop.
+
+To re-enable imap-before-smtp I wrote a little setuid wrapper, calling
+vpopmails open_smtp_relay(). This wrapper has to replace the imapd command in
+your courier-imap startup script and will exec imapd, after opening the smtp
+relay, wile imap-login is still in place to authenticate via authdaemond's
+vchkpw module.
+
+```c
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <vpopmail_config.h>
+#include <vauth.h>
+#include <vpopmail.h>
+
+#ifndef IMAPD
+# define IMAPD "/usr/bin/imapd"
+#endif
+
+extern char **environ;
+
+int main(int argc, const char *argv[]) {
+ if (argc != 2) {
+ printf("1 NO argc != 2n");
+ return -1;
+ }
+
+ open_smtp_relay();
+ /* no need to chown vpopmail.vchkpw the open-smtp file
+ * because vchkpw used by qmail-pop3d is setuid root */
+
+ sleep(1);
+
+ if (setgid(VPOPMAILGID) || setuid(VPOPMAILUID)) {
+ printf("1 NO setuid/gid, getuid=%dn", getuid());
+ return -2;
+ }
+
+ execl(IMAPD, IMAPD, argv[1], NULL);
+
+ printf("1 NO exec %s failedn", IMAPD);
+ return -3;
+}
+```
+
+So while this worked to my satisfaction, I noticed that the tcp.smtp.cdb not
+always contained the IPs of the open-smtp file:
+```sh
+$ for ip in $(sed -re 's/:.*//' < open-smtp); do
+ cdbget $ip < tcp.smtp.cdb > /dev/null
+ || echo "$ip is missing";
+ done
+```
+
+I also found out that, while the [vpopmail FAQ](http://www.inter7.com/vpopmail/FAQ.txt) is claiming
+that clearopensmtp is requesting locks on the open-smtp(.lock) file, the source does not read like
+it would.
+
+I opened a [bug report](https://sourceforge.net/tracker/?func=detail&aid=3205655&group_id=85937&atid=577798)
+for that issue, but as you might have already guessed, I'm running all of this
+on an archaic debian box, where no upgrades are planned. So I came up with
+another home-brewed solution:
+
+```c
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <vpopmail_config.h>
+#include <vauth.h>
+#include <vpopmail.h>
+#include <fcntl.h>
+
+extern int get_write_lock(FILE*);
+extern int lock_reg(int,int,int,off_t,int,off_t);
+#define unlock(F) lock_reg(fileno(F), F_SETLK, F_UNLCK, 0, SEEK_SET, 0)
+
+int main(int argc, const char *argv[]) {
+ FILE *fs_temp, *fs_smtp, *fs_lock = fopen(OPEN_SMTP_LOK_FILE, "w+");
+ time_t clear = RELAY_CLEAR_MINUTES * 60, now = time(NULL);
+ int cc = 0, rc = 0;
+
+ if (!fs_lock) {
+ return -1;
+ }
+ if (get_write_lock(fs_lock)) {
+ unlock(fs_lock);
+ fclose(fs_lock);
+ return -2;
+ }
+
+ if (!(fs_temp = fopen(OPEN_SMTP_TMP_FILE ".clear", "w"))) {
+ rc = -3;
+ } else if (!(fs_smtp = fopen(OPEN_SMTP_CUR_FILE, "r+"))) {
+ fclose(fs_temp);
+ rc = -4;
+ } else {
+ while (!rc && !feof(fs_smtp)) {
+ unsigned stime;
+ char sdata[256];
+
+ switch (fscanf(fs_smtp, "%255st%un", sdata, &stime)) {
+ case 2:
+ if ((clear + stime) >= now) {
+ fprintf(fs_temp, "%st%un", sdata, stime);
+ } else {
+ ++cc;
+ }
+ break;
+
+ default:
+ rc = -5;
+ case EOF:
+ break;
+ }
+ }
+ fclose(fs_smtp);
+ fclose(fs_temp);
+ }
+
+ if (!rc) {
+ if (cc) {
+ if (rename(OPEN_SMTP_TMP_FILE ".clear", OPEN_SMTP_CUR_FILE)) {
+ rc = -6;
+ } else if(update_rules()) {
+ rc = -7;
+ }
+ } else {
+ unlink(OPEN_SMTP_TMP_FILE ".clear");
+ }
+ }
+
+ unlock(fs_lock);
+ fclose(fs_lock);
+ return rc;
+}
+```
+
+It's not the prettiest piece of code, but it helps.
+Well, maybe someone else running last-millenium software finds this useful
+
--- /dev/null
+---
+title: Javascript delaying
+author: m6w6
+tags:
+- WEB
+---
+
+In need of executing Javascript after the page has loaded, or something else
+has been initialized I came up with a simple but useful tiny "Delayer":
+
+```js
+/**
+ * @param handler a callback accepting Delayer.dispatch as argument
+ */
+function Delayer(handler) {
+ var self = this;
+
+ this.dispatch = function() {
+ for (var i = 0; i < self.length; ++i) {
+ console.log("running delayed init "+i+": "+self[i]);
+ self[i]();
+ }
+ };
+
+ if (typeof handler == "function" || handler instanceof Function) {
+ handler(this.dispatch);
+ }
+}
+
+Delayer.prototype = Array.prototype;
+```
+
+It can be initialized the following way:
+```js
+/* e.g. with jQuery */
+window.delayedInits = new Delayer($(document).ready);
+/* e.g. with Facebook */
+window.fbDelayedInits = new Delayer(function(dp){window.fbAsyncInit = dp;});
+```
+
+Then you push your work the usual way:
+```js
+delayedInits.push(function() {alert("Hello, delayed!");});
+```
--- /dev/null
+---
+title: pecl_http-v2 - http2 or httpi or http-*
+author: m6w6
+tags:
+- PHP
+---
+
+I'm pondering to release v2 of pecl_http with a different
+extension name than "http", but I cannot agree with myself what's worse:
+
+### http2
+
+This might be confused with HTTP/2.0
+
+### httpi
+
+There's mysqli following this approach, but I think this is pretty odd.
+
+### Split it up
+
+Split the package up in several smaller sub-packages, like:
+
+ * http-common
+ * http-env
+ * http-client
+ * http-client-curl
+ * etc.
+
+If you have an opinion, or maybe even a better idea, please leave a comment.
--- /dev/null
+---
+title: pecl_http-1.7.5
+author: m6w6
+tags:
+- PHP
+---
+
+[pecl_http-1.7.5](http://pecl.php.net/package/pecl_http/1.7.5) has been
+released today.
+
+Nearly a year and 170k downloads after the last release (1.7.4 was released
+April 2nd 2012).
+
+It fixes a single bug:
+
+ * [Bug #64310](http://bugs.php.net/64310) (weak etags W/"abc" are quoted as "W/"abc"")
+
+
+The same user (thanks Niko), discovered a peculiarity of libcurl:
+
+ * If you utilize libcurl's _TIMECOND_ feature through pecl_http's _lastmodified_ request option,
+ libcurl ignores response bodies from servers that do not closely follow the RFC and send a _200 OK_
+ response instead of a _304 Not Modified_ when the condition is unmet.
+
+Slightly more background information is available at the relevant [bug
+report](http://bugs.php.net/64298).
+
+
+Please leave a comment, if you have an opinion about which component's
+behavior is arguable here.
--- /dev/null
+---
+title: Hear, hear
+author: m6w6
+tags:
+- PHP
+scripts:
+- https://platform.twitter.com/widgets.js
+---
+
+I was about to write "in early February" but actually it already was in late January
+that I stumbled over this tweet:
+
+<blockquote class="twitter-tweet" markdown="1">
+I'm still ready & willing to hire a
+[#PHP](https://twitter.com/search?q=%23PHP&src=hash) internals coder to work
+on PHP fulltime. Amazing place to work: <http://t.co/GX4wtPSc>
+
+— Don MacAskill (@DonMacAskill) [January 18, 2013](https://twitter.com/DonMacAskill/statuses/292117608076021760)
+</blockquote>
+
+Fast-forward five months – now I am very excited to be able to announce that
+the Awesomes over at [SmugMug, Inc](http://www.smugmug.com/). have hired me to
+work full-time on the core of PHP.
+
+Hide [bugs.php.net](http://bugs.php.net/), expect massive amounts of commits,
+sleep well. Thank you for reading the simple words of the proudest man alive.
+Thank you SmugMug!
+
--- /dev/null
+---
+title: Evolution of $
+author: m6w6
+tags:
+- PHP
+---
+
+Today I realized an important and probably very obvious fact: we all change. Of
+course, you will say. Surely most of us will agree to that, but the important
+thing about that is also realizing that we drift away from things we loved.
+Okay, so what am I actually talking about? :)
+
+I talk about software development, specifically development of and with PHP.
+We've seen some radical proposals in the nearer past and in deed are still
+seeing those for PHP, the language. Often, I was inclined to think "cool,
+that's a great idea, let's improve in that direction."
+
+PHP was and is a huge success, it attracts a lot of awesome people, sometimes
+becoming unhappy with the language's principles and resulting limitiations,
+like its simplicity, its forgiving nature and the enigne's effort to come to
+an end for this request, i.e. to die. Looking at the larger frameworks which
+have evolved the last few years, they head into a clear direction: strictly
+object oriented programming with
+RidiculouslyLongClassNamesLikeFoundInOtherStrictlyObjectOrientedLanguages.
+Anything non object oriented seems to be verboten. But this is not of what PHP
+was meant to be and it is very hard to change something that late in the game
+in such drastical ways. I don't think PHP can change as fast as we do, it's
+actually much longer around than most of us call ourself programmers.
+
+What I mean to say is, don't be angry with PHP the language, don't force it to
+change in a way it's not supposed to survive, stop proposing language level
+changes in a weekly manner, don't be afraid to change yourself. Don't be
+afraid to advance yourself. Don't be afraid to change the language you program
+in. BOOM, I said it. Yes, don't be afraid to explore other possibilities that
+better support your principles instead of fighting them.
+
+I'm not saying go away, I'm saying go ahead, or at least I mean to.
+
+Sorry for the fast write-up, all the typos and errors. Have a nice start into
+your week!
+
--- /dev/null
+---
+title: Testing PHP extensions on Travis-CI
+author: m6w6
+tags:
+- PHP
+---
+
+Testing PECL extensions on Travis-CI has always been
+cumbersome for me; build PHP in different versions and debug/threadsafe
+flavors, install PECL dependencies and so on, which usually results in a mess
+of command line scripts, repeated for every extension.
+
+Enter [travis-pecl](https://github.com/m6w6/travis-pecl).
+
+This tiny support bin comes with a Makefile and small PHP scripts to generate
+the build matrix and check your package.xml file. It supports building PHP in
+a wide variety of flavors, installing PECL dependencies from the PECL website
+or from bundled [pharext](https://github.com/m6w6/pharext) packages and
+running the testsuite with a comprehensive set of commands.
+
+Let's look at a few commands with a properly set up environment from the test
+matrix:
+
+```yaml
+env:
+ - PHP=5.6 enable_debug=yes with_iconv=yes enable_json=yes
+```
+
+### Build PHP:
+```sh
+make -f travis/pecl/Makefile php
+```
+### Install a PECL dependency:
+```sh
+make -f travis/pecl/Makefile pecl PECL=propro
+```
+### Install a PECL dependency from a [pharext](https://github.com/m6w6/pharext) package, located in travis/:
+```sh
+make -f travis/pecl/Makefile pharext/raphf-phpng
+```
+### Build the currently checked out extension:
+```sh
+make -f travis/pecl/Makefile ext PECL=http
+```
+### Run the testsuite:
+```sh
+make -f travis/pecl/Makefile test
+```
+
+Finally, check out the [README](https://github.com/m6w6/travis-pecl/blob/master/README.md)
+and have a look at a couple of complete examples here:
+
+ * [ext-apfd/gen_travis_yml.php](https://github.com/m6w6/ext-apfd/blob/master/gen_travis_yml.php)
+ * [ext-http/scripts/gen_travis_yml.php](https://github.com/m6w6/ext-http/blob/master/scripts/gen_travis_yml.php)
--- /dev/null
+---
+title: Blank DELL on DisplayPort
+author: m6w6
+tags:
+- WTF
+- SYS
+---
+
+I've been struggling since ever with my DELL U3014 on the DisplayPort
+saying there's no signal after a power cycle of the monitor.
+
+I just found a solution to bring the monitor back to life without rebooting
+the box; just ssh into and issue:
+
+```shell
+$ DISPLAY=:0 xset dpms force off
+$ DISPLAY=:0 xset dpms force on
+```
+
+I'm running Gnome3 on Arch Linux, so YMMV.
--- /dev/null
+---
+title: 'Debian: disabling SSLv3 in courier server'
+author: m6w6
+tags:
+- WTF
+- SYS
+---
+
+Debian wheezy (currently oldstable) ships courier-0.68 which was probably released on 2012.
+"Probably", because, head over to the [Courier website](http://www.courier-mta.org/) and
+try to find the NEWS/ChangeLog.
+
+## The Problem
+
+Anyway. Courier-0.68 has built-in openssl support on Debian and it initializes a SSL
+context the following way:
+
+```c
+ctx=SSL_CTX_new(protocol && strcmp(protocol, "SSL3") == 0
+ ? SSLv3_method():
+ protocol && strcmp(protocol, "SSL23") == 0
+ ? SSLv23_method():
+ TLSv1_method());
+
+// ...
+SSL_CTX_set_options(ctx, SSL_OP_ALL);
+
+if (!ssl_cipher_list)
+ ssl_cipher_list="SSLv3:TLSv1:HIGH:!LOW:!MEDIUM:!EXP:!NULL:!aNULL@STRENGTH";
+
+SSL_CTX_set_cipher_list(ctx, ssl_cipher_list);
+```
+
+#### Some clarifications:
+
+* `SSLv3_method` would **only** allow SSLv3
+* `TLSv1_method` would **only** allow TLSv1.0
+* `SSLv23_method` is "the general-purpose version-flexible SSL/TLS method"
+
+So, if we do not want to limit ourselves to TLSv1.0, i.e. allow TLSv1.0, TLSv1.1 and TLSv1.2,
+we have to limit our protocol version support through other means.
+
+Openssl-1.0.1 (remember, we're on Debian wheezy) does neither come with `TLS_method()` the
+generic TLS-only method, nor does it come with `SSL_CTX_set_min_proto_version` and we cannot
+disable SSLv3 with the cipher list if we also want to allow TLSv1.0.
+
+## Solution 1: Upgrading to Jessie
+
+What if we upgrade to Debian jessie (current stable)? Jessie ships courier-0.73, so let's see
+how SSL context intitialization looks there:
+
+```c
+options=SSL_OP_ALL;
+
+method=((!protocol || !*protocol)
+ ? NULL:
+ strcmp(protocol, "SSL3") == 0
+ ? SSLv3_method():
+ strcmp(protocol, "SSL23") == 0
+ ? SSLv23_method():
+ strcmp(protocol, "TLSv1") == 0
+ ? TLSv1_method():
+#ifdef HAVE_TLSV1_1_METHOD
+ strcmp(protocol, "TLSv1.1") == 0
+ ? TLSv1_1_method():
+#endif
+#ifdef HAVE_TLSV1_2_METHOD
+ strcmp(protocol, "TLSv1.2") == 0
+ ? TLSv1_2_method():
+#endif
+ NULL);
+
+if (!method)
+{
+ method=SSLv23_method();
+ options|=SSL_OP_NO_SSLv2;
+}
+
+ctx=SSL_CTX_new(method);
+
+// ...
+SSL_CTX_set_options(ctx, options);
+
+if (!ssl_cipher_list)
+ ssl_cipher_list="SSLv3:TLSv1:HIGH:!LOW:!MEDIUM:!EXP:!NULL:!aNULL@STRENGTH";
+
+SSL_CTX_set_cipher_list(ctx, ssl_cipher_list);
+```
+
+Jessie also comes with openssl-1.0.1, so the situation would not improve for our undertaking
+by upgrading to jessie.
+
+## Solution 2: Augmenting SSL_CTX_new
+
+What I came up with, is augmenting `SSL_CTX_new` and setting the desired `SSL_OP_NO_SSLv3` on
+each newly created SSL context.
+
+```c
+#include <stdio.h>
+#include <dlfcn.h>
+#include <openssl/ssl.h>
+
+static void *lib;
+static void *new_sym;
+static void *opt_sym;
+
+static void dl() {
+ char *error;
+
+ if (!lib) {
+ lib = dlopen("libssl.so", RTLD_LAZY|RTLD_LOCAL);
+ if (!lib) {
+ fprintf(stderr, "dlopen: %s\n", dlerror());
+ exit(1);
+ }
+ dlerror();
+ }
+
+ if (!new_sym) {
+ *(void **) &new_sym = dlsym(lib, "SSL_CTX_new");
+ if ((error = dlerror())) {
+ fprintf(stderr, "dlsym: %s\n", error);
+ dlclose(lib);
+ exit(1);
+ }
+ }
+
+ if (!opt_sym) {
+ *(void **) &opt_sym = dlsym(lib, "SSL_CTX_ctrl");
+ if ((error = dlerror())) {
+ fprintf(stderr, "dlsym: %s\n", error);
+ dlclose(lib);
+ exit(1);
+ }
+ }
+}
+
+SSL_CTX *SSL_CTX_new(const SSL_METHOD *m)
+{
+ SSL_CTX *ctx;
+
+ dl();
+
+ ctx = ((SSL_CTX *(*)(const SSL_METHOD*))new_sym)(m);
+
+ if (ctx) {
+ ((long (*)(SSL_CTX *, int, long, void*))opt_sym)(ctx, SSL_CTRL_OPTIONS, SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3, NULL);
+ }
+ return ctx;
+}
+```
+
+This is the source of a tiny shared library pre-defining our `SSL_CTX_new`; to build like e.g.
+
+`gcc -ldl -fPIC -shared -o preload.so preload.c`
+
+It does the following:
+
+* augments `SSL_CTX_new` with our own version,
+ i.e. whenever courier calls `SSL_CTX_new` our own version gets called
+* when it's called the first time, it
+ * `dlopen`'s libssl
+ * fetches the addresses of the original `SSL_CTX_new` and `SSL_CTX_ctrl`
+ (which is the actual function `SSL_CTX_set_options` calls)
+* calls the original `SSL_CTX_new` to actually create the SSL context
+* calls `SSL_CTX_ctrl` on the new context with the options we want to set (`SSL_OP_NO_SSLv3`)
+* returns the context to the caller
+
+### Usage
+
+Courier config files are basically shell scripts which set a environment variables, so we'll
+enable it as follows:
+
+```sh
+cd /etc/courier
+cat >>esmtpd >>esmtpd-msa >>esmtpd-ssl \
+ >>pop3d >>pop3d-ssl \
+ >>imapd >>imapd-ssl \
+ >>courierd <<EOF
+LD_PRELOAD=/path/to/preload.so
+EOF
+```
+
+Then restart each courier service.
+
+### Verifying
+
+Last, we have to verify that our solution actually works:
+
+```sh
+openssl s_client \
+ -CApath /etc/ssl/certs/ \
+ -starttls imap \
+ -connect localhost:143 \
+ -crlf -quiet -ssl3 \
+ <<<LOGOUT
+139690858608296:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:s3_pkt.c:1261:SSL alert number 40
+139690858608296:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:s3_pkt.c:599:
+```
+
+A bunch of errors. "Good"! :)
+
+Let's see if we can still connect with TLSv1+:
+
+```sh
+openssl s_client \
+ -CApath /etc/ssl/certs/ \
+ -starttls imap \
+ -connect localhost:143 \
+ -crlf -quiet -tls1 \
+ <<<LOGOUT
+depth=2 ...
+verify return:1
+depth=1 ...
+verify return:1
+depth=0 ...
+verify return:1
+. OK CAPABILITY completed
+* BYE Courier-IMAP server shutting down
+LOGOUT OK LOGOUT completed
+```
+
+Awesome. Mission accomplished.
+
+## Addendum
+
+Here's my cipher list for the interested:
+
+```sh
+openssl ciphers -v 'HIGH+aRSA:+kEDH:+kRSA:+SHA:+3DES:!kSRP' \
+ | awk '{ printf "%-28s %-8s %-8s %-18s %-16s\n",$1,$2,$3,$5,$6 }'
+```
+
+Which results in the following ciphers:
+
+```
+ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Enc=AESGCM(256) Mac=AEAD
+ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Enc=AES(256) Mac=SHA384
+ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Enc=AESGCM(128) Mac=AEAD
+ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Enc=AES(128) Mac=SHA256
+DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH Enc=AESGCM(256) Mac=AEAD
+DHE-RSA-AES256-SHA256 TLSv1.2 Kx=DH Enc=AES(256) Mac=SHA256
+DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH Enc=AESGCM(128) Mac=AEAD
+DHE-RSA-AES128-SHA256 TLSv1.2 Kx=DH Enc=AES(128) Mac=SHA256
+AES256-GCM-SHA384 TLSv1.2 Kx=RSA Enc=AESGCM(256) Mac=AEAD
+AES256-SHA256 TLSv1.2 Kx=RSA Enc=AES(256) Mac=SHA256
+AES128-GCM-SHA256 TLSv1.2 Kx=RSA Enc=AESGCM(128) Mac=AEAD
+AES128-SHA256 TLSv1.2 Kx=RSA Enc=AES(128) Mac=SHA256
+ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Enc=AES(256) Mac=SHA1
+ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Enc=AES(128) Mac=SHA1
+DHE-RSA-AES256-SHA SSLv3 Kx=DH Enc=AES(256) Mac=SHA1
+DHE-RSA-CAMELLIA256-SHA SSLv3 Kx=DH Enc=Camellia(256) Mac=SHA1
+DHE-RSA-AES128-SHA SSLv3 Kx=DH Enc=AES(128) Mac=SHA1
+DHE-RSA-CAMELLIA128-SHA SSLv3 Kx=DH Enc=Camellia(128) Mac=SHA1
+AES256-SHA SSLv3 Kx=RSA Enc=AES(256) Mac=SHA1
+CAMELLIA256-SHA SSLv3 Kx=RSA Enc=Camellia(256) Mac=SHA1
+AES128-SHA SSLv3 Kx=RSA Enc=AES(128) Mac=SHA1
+CAMELLIA128-SHA SSLv3 Kx=RSA Enc=Camellia(128) Mac=SHA1
+ECDHE-RSA-DES-CBC3-SHA SSLv3 Kx=ECDH Enc=3DES(168) Mac=SHA1
+EDH-RSA-DES-CBC3-SHA SSLv3 Kx=DH Enc=3DES(168) Mac=SHA1
+DES-CBC3-SHA SSLv3 Kx=RSA Enc=3DES(168) Mac=SHA1
+```
+
+Note, that courier actually does **not** support `ECDH` key exchange, but I didn't exclude it for
+the sake of simplicity for using the same cipher list for every server (e.g. web etc.)
--- /dev/null
+$view-backgroud-color: #000;
+$page-background-color: rgba(255, 255, 255, 0.90);
+$code-background-color: rgba(255, 255, 255, 0.50);
+
+$shadow-color: #666;
+$border-color: #ccc;
+
+$header-color: #000;
+$body-color: #000;
+$code-color: #821;
+
+$a-link-color: #178;
+$a-active-color: #182;
+$a-visited-color: #218;
+$a-hover-color: #182;
+
+@media (prefers-color-scheme: light) {
+ :root {
+ --view-backgroud-color: #000;
+ --page-background-color: rgba(255, 255, 255, 0.90);
+ --code-background-color: rgba(255, 255, 255, 0.50);
+
+ --shadow-color: #666;
+ --border-color: #ccc;
+
+ --header-color: #000;
+ --body-color: #000;
+ --code-color: #821;
+
+ --a-link-color: #178;
+ --a-active-color: #182;
+ --a-visited-color: #218;
+ --a-hover-color: #182;
+ }
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --view-backgroud-color: #000;
+ --page-background-color: rgba(17, 17, 17, 0.90);
+ --code-background-color: rgba(102, 102, 102, 0.50);
+
+ --shadow-color: #666;
+ --border-color: #999;
+
+ --header-color: #f0f0f0;
+ --body-color: #ddd;
+ --code-color: #c43;
+
+ --a-link-color: #8df;
+ --a-active-color: #8f9;
+ --a-visited-color: #98f;
+ --a-hover-color: #8f9;
+ }
+}
--- /dev/null
+@import "_colors";
+
+.email:after {
+ content: "\6d\69\6b\65\40\70\68\70\2e\6e\65\74";
+}
+.jabber:after {
+ content: "\6d\36\77\36\40\6a\61\62\62\65\72\2e\63\63\63\2e\64\65";
+}
+.twitter-tweet-rendered {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.pubinfo, .breadcrumbs {
+ font-style: italic;
+ opacity: .7;
+}
+
+.cc-sa img {
+ border: none;
+ vertical-align: middle;
+}
--- /dev/null
+$body-font: 'Linux Biolinum';
+$header-font: 'Linux Libertine Display', Georgia, 'Times New Roman', Times, serif;
+$code-font: 'DejaVu Sans Mono', 'Bitstream Vera Mono', 'Menlo', 'Consolas', 'Andale Mono', 'Lucida Console', 'Monospace', monospace;
+
+//$font-size: 14px;
+//$line-height: 130%;
+$font-size: 12px;
+$line-height: 180%;
+
+@font-face {
+ font-family: 'Linux Libertine Display';
+ src: url('subset-LinLibertineDisplay.woff2') format('woff2'), url('subset-LinLibertineDisplay.woff') format('woff');
+ font-weight: normal;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: 'Linux Biolinum';
+ src: local('Linux Biolinum Italic'), local('LinBiolinumI'),
+ url('subset-LinBiolinumI.woff2') format('woff2'),
+ url('subset-LinBiolinumI.woff') format('woff');
+ font-weight: normal;
+ font-style: italic;
+}
+
+@font-face {
+ font-family: 'Linux Biolinum';
+ src: local('Linux Biolinum'), local('LinBiolinum'),
+ url('subset-LinBiolinum.woff2') format('woff2'),
+ url('subset-LinBiolinum.woff') format('woff');
+ font-weight: normal;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: 'Linux Biolinum';
+ src: local('Linux Biolinum Bold'), local('LinBiolinumB'),
+ url('subset-LinBiolinumB.woff2') format('woff2'),
+ url('subset-LinBiolinumB.woff') format('woff');
+ font-weight: bold;
+ font-style: normal;
+}
--- /dev/null
+@import '_colors';
+@import '_fonts';
+@import '_common';
+
+html {
+ background: $view-backgroud-color url("lapalma-c.jpg") fixed no-repeat;
+ background: var(--view-backgroud-color) url("lapalma-c.jpg") fixed no-repeat;
+ background-size: cover;
+ height: 100%;
+ font-size: $font-size;
+}
+
+body {
+ font-family: $body-font;
+ line-height: $line-height;
+ margin: 0;
+ color: $body-color;
+ color: var(--body-color);
+
+ &.default {
+ display: block;
+ }
+ >div {
+ background: $page-background-color;
+ background: var(--page-background-color);
+ max-width: 1000px;
+ margin: 0 auto;
+ header>h1 {
+ margin-top: 0;
+ }
+ }
+}
+
+@mixin responsive($rel-size) {
+ body {
+ font-size: $rel-size;
+ >div {
+ padding: $rel-size;
+ }
+ }
+ section {
+ margin-top: $rel-size;
+ }
+ p {
+ margin: $rel-size;
+ }
+ ul li {
+ margin-left: $rel-size;
+ }
+ dd+dt {
+ margin-top: $rel-size/4;
+ }
+ th, td {
+ padding: $rel-size;
+ .career-table & {
+ padding: $rel-size/10 $rel-size/2;
+ }
+ }
+ h1, h2, h3, h4, h5, h6, th {
+ text-shadow: 0 0 $rel-size/3 $shadow-color;
+ }
+ h2+h3, h3+h4, h4+h5, h5+h6 {
+ margin-top: -$rel-size/2;
+ }
+ h2~h3 {
+ margin-left: $rel-size/4;
+ }
+ h3~h4 {
+ margin-left: $rel-size/2;
+ }
+ h4~h5 {
+ margin-left: $rel-size;
+ }
+ h5~h6 {
+ margin-left: $rel-size;
+ }
+ h2 {
+ padding-top: $rel-size;
+ }
+ pre {
+ padding: 0 $rel-size;
+ code {
+ padding: $rel-size !important;
+ font-size: $rel-size/1.66;
+ border-radius: $rel-size/2;
+ box-shadow: 0 0 $rel-size/4 $shadow-color;
+ box-shadow: 0 0 $rel-size/4 var(--shadow-color);
+ }
+ }
+ code {
+ padding: $rel-size/20 $rel-size/10;
+ font-size: $rel-size/1.5;
+ border-radius: $rel-size/5;
+ }
+ .cc-sa {
+ font-size: $rel-size/2;
+ margin-top: $rel-size*2;
+ }
+ .pubinfo, .breadcrumbs {
+ font-size: $rel-size/1.5;
+ margin: -$rel-size 0 $rel-size $rel-size*2;
+ }
+ .box-of-links a {
+ line-height: 2*$rel-size;
+ min-width: 8*$rel-size;
+ svg {
+ width: $rel-size*1.5;
+ height: $rel-size*1.5;
+ }
+ &.gnupg svg {
+ width: $rel-size*1.8;
+ height: $rel-size*1.8;
+ }
+ &.jabber svg {
+ width: $rel-size*1.8;
+ height: $rel-size*1.8;
+ }
+ &.flattr-com svg {
+ height: $rel-size*1.2;
+ }
+ &.openhub-net svg {
+ height: $rel-size*1.3;
+ }
+ &.smugmug-com svg {
+ height: $rel-size*1.2;
+ }
+ }
+}
+
+@media (min-width: 1440px) {
+ @include responsive(1.8rem);
+}
+@media (max-width: 1440px) {
+ @include responsive(1.7rem);
+}
+@media (max-width: 1280px) {
+ @include responsive(1.6rem);
+}
+@media (max-width: 1080px) { /* includes 1024, 900 */
+ @include responsive(1.5rem);
+}
+@media (max-width: 800px) { /* includes 768 */
+ @include responsive(1.4rem);
+}
+@media (max-width: 720px) {
+ @include responsive(1.3rem);
+}
+
+h1, h2, h3, h4, h5, h6, th {
+ font-family: $header-font;
+ color: $header-color;
+ color: var(--header-color);
+ font-weight: normal;
+ line-height: 110%;
+}
+
+h2 {
+ border-top: 1px solid $border-color;
+ border-top: 1px solid var(--border-color);
+}
+
+ul {
+ li {
+ list-style-type: circle;
+ li {
+ margin-left: auto;
+ }
+ }
+}
+
+header, main, section, footer {
+ clear: both;
+}
+
+footer {
+ text-align: center;
+ opacity: .5;
+}
+
+
+code {
+ font-family: $code-font;
+ color: $code-color;
+ color: var(--code-color);
+ background: $code-background-color;
+ background: var(--code-background-color);
+}
+pre {
+ code {
+ background: black;
+ color: lime;
+ display: inline-block !important;
+ box-sizing: border-box;
+ max-width: 100%;
+ line-height: 133%;
+ }
+}
+
+dt {
+ font-weight: bold;
+}
+
+.presence-table svg {
+ vertical-align: middle;
+}
+
+.career-table {
+
+ min-width: 80%;
+ border-spacing: 0;
+ th {
+ border-left: 1rem solid $border-color;
+ border-left: 1rem solid var(--border-color);
+ font-size: x-small;
+ }
+ tr:first-child th {
+ border-top-left-radius: 2rem;
+ }
+ tr:last-child th {
+ border-bottom-left-radius: 2rem;
+ }
+ tr:nth-child(2) th { opacity: .95; }
+ tr:nth-child(3) th { opacity: .90; }
+ tr:nth-child(4) th { opacity: .85; }
+ tr:nth-child(5) th { opacity: .80; }
+ tr:nth-child(6) th { opacity: .75; }
+ tr:nth-child(7) th { opacity: .70; }
+ tr:nth-child(8) th { opacity: .65; }
+ tr:nth-child(9) th { opacity: .60; }
+ tr:nth-child(10) th { opacity: .55; }
+ tr:nth-child(11) th { opacity: .50; }
+ tr:nth-child(12) th { opacity: .45; }
+ tr:nth-child(13) th { opacity: .40; }
+ tr:nth-child(14) th { opacity: .35; }
+ tr:nth-child(15) th { opacity: .30; }
+ tr:nth-child(16) th { opacity: .25; }
+ tr:nth-child(17) th { opacity: .20; }
+ tr:nth-child(18) th { opacity: .15; }
+ tr:nth-child(n+19):nth-child(-n+99) th { opacity: .1; }
+ tr.career-change {
+ +tr {
+ td {
+ border-top: 1px solid $border-color;
+ border-top: 1px solid var(--border-color);
+ }
+ }
+ }
+}
+table {
+ border: none;
+}
+th, td {
+ text-align: left;
+ vertical-align: middle;
+}
+a {
+ text-decoration: none;
+ &:link {
+ color: $a-link-color;
+ color: var(--a-link-color);
+ }
+ &:visited {
+ color: $a-visited-color;
+ color: var(--a-visited-color);
+ }
+ &:hover {
+ color: $a-hover-color;
+ color: var(--a-hover-color);
+ text-decoration: underline;
+ }
+ &:active {
+ color: $a-active-color;
+ color: var(--a-active-color);
+ }
+ &[rel="external"]:after {
+ content: " ↗";
+ font-size: 1rem;
+ font-weight: bold;
+ }
+ &[download]:after {
+ content: " ↓";
+ font-size: 1rem;
+ font-weight: bold;
+ }
+}
+img#portrait {
+ border: 1px solid #999;
+ box-shadow: 0 0 1em $shadow-color;
+ box-shadow: 0 0 1em var(--shadow-color);
+ margin-right: 1em;
+ margin-bottom: 1em;
+ float: left;
+}
+
+.cc-sa {
+ border-top: 1px solid $border-color;
+ border-top: 1px solid var(--border-color);
+}
+
+a svg {
+ vertical-align: middle;
+}
+.box-of-links {
+ display: flex;
+ flex-wrap: wrap;
+ a {
+ display: block;
+ padding: 1rem;
+ white-space: nowrap;
+ }
+}
--- /dev/null
+@import '_fonts';
+@import '_common';
+
+html {
+ font-size: $font-size;
+ font-family: $code-font;
+ background: #111 url("lapalma-o-10.jpg") fixed no-repeat;
+ background-size: cover;
+ height: 100%;
+ box-sizing: border-box;
+}
+
+body {
+ line-height: $line-height*1.33;
+ background: transparent url("lapalma-o-100.jpg") fixed no-repeat;
+ background-size: cover;
+ min-height: 100%;
+ box-sizing: border-box;
+ margin: 0;
+ padding: 1rem;
+
+ &.post {
+ display: block;
+ }
+
+ >div {
+ max-width: 120ch;
+ border: 1px outset black;
+ border-top-left-radius: 1.33rem;
+ border-top-right-radius: 1.33rem;
+ margin: auto;
+ >header {
+ background: linear-gradient(180deg, rgba(175,175,175,.8), rgba(240,240,240,.8));
+ padding: .33rem;
+ border-top-left-radius: 1rem;
+ border-top-right-radius: 1rem;
+
+ font-family: sans-serif;
+ text-align: center;
+ font-weight: bold;
+
+ display: grid;
+
+ >h1 {
+ grid-column: 1 / 8;
+ margin: 0;
+ font-size: 1.6rem;
+ }
+ >div {
+ grid-column: 9 / 10;
+ text-align: right;
+ margin-right: .5rem;
+ span {
+ display: inline-block;
+ border: 1px solid #000;
+ border-radius: .2rem;
+ background: linear-gradient(0deg, #afafaf, #f0f0f0);
+ width: 1.2rem;
+ line-height: 120%;
+ text-align: center;
+ padding: .1rem;
+ margin: .2rem;
+ animation: 1s linear 0s background;
+ &:hover {
+ background: linear-gradient(180deg, #afafaf, #f0f0f0);
+ }
+ }
+ }
+ }
+ >main {
+ >div {
+ background: #333;
+ color: #eee;
+ font-size: 1.5em;
+ padding: 1rem;
+ p {
+ &::before {
+ content: "~$ \A";
+ color: lime;
+ font-weight: 100;
+ }
+ }
+ blockquote p::before, .pubinfo p::before {
+ content: none;
+ color: white;
+ }
+ blockquote p:first-child::before {
+ content: "» ";
+ vertical-align: baseline;
+ font-size: 4rem;
+ opacity: .33;
+ }
+ blockquote p:last-child::after {
+ content: " «";
+ vertical-align: bottom;
+ font-size: 4rem;
+ opacity: .33;
+
+ }
+ &:last-child::after {
+ content: "_";
+ animation: 1s steps(2,end) 0s infinite blink;
+ }
+
+ h1,h2,h3,h4,h5,h6 {
+ font-weight: normal;
+ font-size: 1em;
+ color: lime;
+ margin-top:2em;
+ &::before {
+ content: "# ";
+ }
+ &::after {
+ content: " ⏎";
+ }
+ }
+ }
+ }
+ }
+
+ >footer {
+ line-height: 150%;
+ text-align: center;
+ max-width: 120ch;
+ margin: auto;
+ border-bottom-left-radius: 1.33rem;
+ border-bottom-right-radius: 1.33rem;
+// background: rgba(255,255,255, .80);
+ background: linear-gradient(0deg, rgba(175,175,175,.8), rgba(240,240,240,.8));
+ border: 1px outset black;
+ }
+}
+
+.pubinfo {
+ text-align: right;
+ font-size: 1rem;
+}
+
+.cc-sa {
+ width: 50%;
+ padding: 1rem;
+ margin: auto;
+}
+
+@keyframes blink {
+ from {background: transparent;}
+ to {background: white;}
+}
+
+a {
+ &:link {
+ color: #00afff;
+ }
+ &:visited {
+ color: #cf00af;
+ opacity: .8;
+ }
+ &:hover {
+ color: #30ff00;
+ }
+}
+
+pre {
+ line-height: 150%;
+ font-size: 1.2rem;
+
+ background: black;
+ color: white;
+
+ border: 1px solid #1c1;
+
+ counter-increment: examples;
+ counter-reset: lines;
+ &::after {
+ background: #1c1;
+ color: black;
+ display: block;
+ content: " example" counter(examples) ".txt " counter(lines) "L 1,1 Top";
+ }
+
+ code {
+ opacity: .8;
+ span.newline {
+ counter-increment: lines;
+ &::before {
+ content: counter(lines) " ";
+ width: 2rem;
+ display: inline-block;
+ text-align: right;
+ opacity: .5;
+ }
+ }
+ padding: 1em 1em 1em 1em;
+ display: block;
+ overflow-x: auto;
+ }
+}
--- /dev/null
+---
+---
+
+@import "index";
--- /dev/null
+---
+---
+
+@import "post";
--- /dev/null
+.highlight table td { padding: 5px; }
+.highlight table pre { margin: 0; }
+.highlight, .highlight .w {
+ color: #f8f8f2;
+ background-color: #272822;
+}
+.highlight .err {
+ color: #272822;
+ background-color: #f92672;
+}
+.highlight .c, .highlight .ch, .highlight .cd, .highlight .cm, .highlight .cpf, .highlight .c1, .highlight .cs {
+ color: #75715e;
+}
+.highlight .cp {
+ color: #f4bf75;
+}
+.highlight .nt {
+ color: #f4bf75;
+}
+.highlight .o, .highlight .ow {
+ color: #f8f8f2;
+}
+.highlight .p, .highlight .pi {
+ color: #f8f8f2;
+}
+.highlight .gi {
+ color: #a6e22e;
+}
+.highlight .gd {
+ color: #f92672;
+}
+.highlight .gh {
+ color: #66d9ef;
+ background-color: #272822;
+ font-weight: bold;
+}
+.highlight .k, .highlight .kn, .highlight .kp, .highlight .kr, .highlight .kv {
+ color: #ae81ff;
+}
+.highlight .kc {
+ color: #fd971f;
+}
+.highlight .kt {
+ color: #fd971f;
+}
+.highlight .kd {
+ color: #fd971f;
+}
+.highlight .s, .highlight .sa, .highlight .sb, .highlight .sc, .highlight .dl, .highlight .sd, .highlight .s2, .highlight .sh, .highlight .sx, .highlight .s1 {
+ color: #a6e22e;
+}
+.highlight .sr {
+ color: #a1efe4;
+}
+.highlight .si {
+ color: #cc6633;
+}
+.highlight .se {
+ color: #cc6633;
+}
+.highlight .nn {
+ color: #f4bf75;
+}
+.highlight .nc {
+ color: #f4bf75;
+}
+.highlight .no {
+ color: #f4bf75;
+}
+.highlight .na {
+ color: #66d9ef;
+}
+.highlight .m, .highlight .mb, .highlight .mf, .highlight .mh, .highlight .mi, .highlight .il, .highlight .mo, .highlight .mx {
+ color: #a6e22e;
+}
+.highlight .ss {
+ color: #a6e22e;
+}
--- /dev/null
+---
+layout: default
+title: "Mike's sudden inspirations"
+permalink: blog.html
+styles: assets/index.css
+---
+{% include head.html %}
+<body class="blog">
+<div>
+ <header>
+ <h1>{{ page.title }}</h1>
+ <p class="breadcrumbs">
+ » <a href="{{ site.url }}">{{ site.title }}</a>
+ </p>
+ </header>
+ <main>
+ {% assign y_posts = site.posts | group_by_exp: "post", "post.date | slice: 0, 4" %}
+ {% for y in y_posts %}
+ <h2 id="{{ y.name }}">{{ y.name }}</h2>
+ {% assign m_posts = y.items | group_by_exp: "item", "item.date | slice: 5, 2" %}
+ {% for m in m_posts %}
+ {% assign month = m.items | map: "date" | first | date: "%B" %}
+ <h3 id="{{ y.name }}{{ m.name }}">{{ month }}</h3>
+ {% assign d_posts = m.items | group_by_exp: "item", "item.date | slice: 8, 2" %}
+ {% for d in d_posts %}
+ {% assign day = d.items | map: "date" | first | date: "%A, %e" %}
+ <h4 id="{{ y.name }}{{ m.name }}{{ d.name }}">{{ day }}</h4>
+ <ul>
+ {% for post in d.items %}
+ <li>
+ <a href=".{{ post.url }}">{{ post.title }}</a> in
+ {% assign last_tag = post.tags | last %}
+ {% for tag in post.tags %}
+ <a class="tag" href="blog/tags/{{ tag }}/"
+ >{{ tag }}</a>{% if tag != last_tag %}, {% endif %}
+ {% endfor %}
+ </li>
+ {% endfor %}
+ </ul>
+ {% endfor %}
+ {% endfor %}
+ {% endfor %}
+ </main>
+ <footer>
+ {% include ccsa.html %}
+ </footer>
+</div>
+</body>
+{% include foot.html %}
--- /dev/null
+---
+title: Michael Wallner (m6w6)
+layout: default
+styles: assets/index.css
+---
+ <header>
+ <div>
+ <img id="portrait" src="m6w6.jpg" height="185" width="140" alt="">
+ </div>
+ <h1>
+ {{ site.title }} <small><<span class="email"></span>></small>
+ </h1>
+ <p>
+ {{ site.description }}
+ </p>
+ </header>
+ <section>
+ <h2 id="identity">Identity</h2>
+ <h3>PGP, GPG</h3>
+ <p><code>1EC3 C71D DD63 5831 A337 D684 480E 3E14 B0A4 C7C7</code></p>
+ <div class="box-of-links">
+ <a href="./openpgp.key" type="text/plain" download="mike@php.net.key"
+ ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="4rem" height="4rem" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M5.83 10A2.99 2.99 0 0 0 3 8a3 3 0 0 0-3 3a3 3 0 0 0 3 3c1.31 0 2.42-.83 2.83-2H8v2h2v-2h1v-2H5.83M3 12a1 1 0 0 1-1-1a1 1 0 0 1 1-1a1 1 0 0 1 1 1a1 1 0 0 1-1 1m13-8a4 4 0 0 0-4 4a4 4 0 0 0 4 4a4 4 0 0 0 4-4a4 4 0 0 0-4-4m0 6.1A2.1 2.1 0 0 1 13.9 8A2.1 2.1 0 0 1 16 5.9a2.1 2.1 0 1 1 0 4.2m0 2.9c-2.67 0-8 1.33-8 4v3h16v-3c0-2.67-5.33-4-8-4m6.1 5.1H9.9V17c0-.64 3.1-2.1 6.1-2.1c2.97 0 6.1 1.46 6.1 2.1v1.1z" fill="#626262"/></svg>
+ pubkey</a>
+ <a href="https://keybase.io/m6w6"
+ rel="external" class="keybase-io"
+ ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="4rem" height="4rem" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M10.446 21.371a.953.953 0 1 1-.955-.954c.524 0 .951.431.951.955m5.922-.001a.953.953 0 1 1-.958-.954c.526 0 .954.431.954.955m4.544-9.159l-.156-.204c-.046-.06-.096-.116-.143-.175c-.045-.061-.094-.113-.141-.169c-.104-.12-.209-.239-.319-.359l-.076-.08l-.091-.099l-.135-.131c-.015-.018-.032-.034-.05-.053a10.87 10.87 0 0 0-3.955-2.504l-.23-.078l.035-.083a4.108 4.108 0 0 0-.12-3.255a4.11 4.11 0 0 0-2.438-2.16c-.656-.216-1.23-.319-1.711-.305c-.033-.105-.1-.577.496-1.848L10.663 0l-.287.399c-.33.455-.648.895-.945 1.328a1.857 1.857 0 0 0-1.245-.58L6.79 1.061h-.012c-.033-.003-.07-.003-.104-.003c-.99 0-1.81.771-1.87 1.755l-.088 1.402v.003a1.876 1.876 0 0 0 1.755 1.979l1.002.061c-.065.84.073 1.62.405 2.306a11.279 11.279 0 0 0-3.66 2.484C.913 14.391.913 18.051.913 20.994v1.775l1.305-1.387c.266.93.652 1.807 1.145 2.615H5.06a9.197 9.197 0 0 1-1.68-3.848l1.913-2.03l-.985 3.091l1.74-1.268c3.075-2.234 6.744-2.75 10.91-1.529c1.805.532 3.56.039 4.473-1.257l.104-.165c.091.498.141.998.141 1.496c0 1.563-.255 3.687-1.38 5.512h1.611c.776-1.563 1.181-3.432 1.181-5.512c-.001-2.199-.786-4.421-2.184-6.274zM8.894 6.191c.123-1.002.578-1.949 1.23-2.97a1.36 1.36 0 0 0 1.283.749c.217-.008.605.025 1.233.232c.714.236 1.286.744 1.608 1.425s.349 1.442.079 2.149c-.173.445-.454.82-.806 1.109l-.408-.502l-.002-.003a1.468 1.468 0 0 0-2.059-.205c-.334.27-.514.66-.534 1.058c-1.2-.541-1.8-1.643-1.628-3.041l.004-.001zm4.304 5.11l-.519.425a.228.228 0 0 1-.323-.032l-.111-.135a.238.238 0 0 1 .034-.334l.51-.42l-1.055-1.299a.307.307 0 0 1 .044-.436a.303.303 0 0 1 .434.041l2.963 3.645a.309.309 0 0 1-.168.499a.315.315 0 0 1-.31-.104l-.295-.365l-1.045.854a.244.244 0 0 1-.154.055a.237.237 0 0 1-.186-.09l-.477-.579a.24.24 0 0 1 .035-.336l1.051-.857l-.426-.533l-.002.001zM7.753 4.866l-1.196-.075a.463.463 0 0 1-.435-.488l.09-1.401a.462.462 0 0 1 .461-.436h.024l1.401.091a.459.459 0 0 1 .433.488l-.007.101a9.269 9.269 0 0 0-.773 1.72h.002zm12.524 11.481c-.565.805-1.687 1.081-2.924.718c-3.886-1.141-7.396-.903-10.468.701l1.636-5.123l-5.291 5.609c.099-3.762 2.453-6.966 5.758-8.311c.471.373 1.034.66 1.673.841c.16.044.322.074.48.102a1.41 1.41 0 0 0 .21 1.407l.075.09c-.172.45-.105.975.221 1.374l.475.582a1.39 1.39 0 0 0 1.079.513c.321 0 .635-.111.886-.314l.285-.232c.174.074.367.113.566.113a1.45 1.45 0 0 0 .928-.326c.623-.51.72-1.435.209-2.06l-1.67-2.056c.145-.117.281-.244.408-.381c.135.037.271.078.4.12c.266.097.533.198.795.315a9.55 9.55 0 0 1 2.771 1.897c.029.03.059.055.085.083l.17.175a9.168 9.168 0 0 1 .35.387l.126.15c.045.053.086.104.13.16l.114.15c.04.051.079.102.117.154c.838 1.149.987 2.329.404 3.157v.005zM7.719 4.115l-.835-.051l.053-.835l.834.051l-.052.835z" fill="#626262"/></svg>
+ keybase.io</a>
+ <!-- a href="https://sks-keyservers.net/pks/lookup?op=vindex&search=0xB0A4C7C7&fingerprint=on"
+ rel="external" class="gnupg"
+ ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="4rem" height="4rem" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 70 70"><path d="m173.45252,38.04702zm-158.54822,-4.85442l2.8387,0l0,-8.5449c0,-9.5791 7.7686,-17.3477 17.3476,-17.3477c9.5793,0 17.3474,7.7686 17.3474,17.3477l0,8.4605c-0.041,0.0287 -0.0818,0.0568 -0.122,0.0844l0.0003,0l-0.0264,0.0178l-0.003,0.002l-0.003,0.0017l-0.003,0.0019l-0.0131,0.009l-0.0155,0.0105l-0.003,0.0021l-0.017,0.0115l-0.0008,0.0006l-0.007,0.0045l-0.004,0.0025l-0.008,0.0057l-0.002,0.0013l-0.0103,0.0069l-0.0001,0l-0.0103,0.007l-0.0139,0.0093l-0.007,0.0045l-0.006,0.0037l-0.005,0.0031l-0.0156,0.0106l-0.0151,0.0099l-0.0007,0.0005l-0.0196,0.013l-0.004,0.0028l-0.0239,0.0157l-0.002,0.0014l-0.01,0.0065l-0.0003,0.0002l-0.004,0.0024l-0.0313,0.0205l-0.005,0.0032l-0.007,0.0045l-0.003,0.0019l-0.002,0.0015l-0.0161,0.0105l-0.002,0.0009l-0.0004,0.0003l-0.001,0.0006l-0.0184,0.0119l-0.004,0.0025l-0.006,0.0038l-0.006,0.0035l-0.004,0.0027l-0.01,0.0063l-0.009,0.0058l-0.0007,0.0003l-0.01,0.0063l-0.001,0.0007l-0.009,0.0054l-0.003,0.0018l-0.007,0.0045l-0.005,0.0028l-0.005,0.0032l-0.006,0.0039l-0.004,0.0022l-0.0527,0.0331l-0.0112,0.0068l-0.003,0.0017l-0.0282,0.0175l-0.002,0.0014l-0.0321,0.0195l-0.0008,0.0005l-0.002,0.0014l-0.009,0.0052l-0.0005,0.0003l-0.009,0.0056l-0.001,0.0006l-0.008,0.0049l-0.008,0.0048l-0.001,0.0007l-0.004,0.0026l-0.0139,0.0083l-0.007,0.0045l-0.0106,0.0064l-0.031,0.0182l-0.031,0.0182l-0.0312,0.0183l-0.0312,0.0184l-0.063,0.0368l-0.0317,0.0184l-0.0318,0.0186l-0.0132,0.0076l-0.0831,0.048l-0.0323,0.0186l-0.0326,0.0186l-0.0326,0.0188l-0.0429,0.0245l-0.056,0.0317l-0.0332,0.0188l-0.129,0.0725l-0.006,0.003l-0.034,0.0189l-0.034,0.0191l-0.008,0.0042l-0.0453,0.025l-0.1017,0.0559l-0.0478,0.0262c-0.0488,0.0265 -0.0981,0.0532 -0.1479,0.0799l-0.0127,0.0069l-0.0232,0.0124l-0.0724,0.0385l-0.0364,0.0194l-0.006,0.0032l-0.0669,0.0353l-0.0003,0.0002l-0.037,0.0193l-0.0106,0.0055l-0.0638,0.0334l-0.0374,0.0194l-0.0343,0.0177c-0.0467,0.0242 -0.0939,0.0484 -0.1415,0.0726l-0.0389,0.0198c-0.0559,0.0283 -0.1124,0.0568 -0.1695,0.0852l-0.0005,0.0002c-0.0545,0.0271 -0.1095,0.0543 -0.1651,0.0815l-0.0552,0.027c-0.0604,0.0293 -0.1213,0.0589 -0.183,0.0884l-0.0003,0c-3.445,1.6457 -8.9698,3.3967 -19.458,4.1496c-7.5135,0.5398 -12.0684,3.8468 -15.0393,7.8378l0,-13.6174l0.0043,0zm10.8293,0l18.7139,0l0,-8.5449c0,-5.1671 -4.19,-9.3571 -9.3569,-9.3571c-5.1668,0 -9.357,4.19 -9.357,9.3571l0,8.5449zm24.2416,1.3477c-0.056,0.0283 -0.1123,0.0567 -0.1695,0.0852m-6.8566,-23.1288c-2.2246,-1.3293 -4.8253,-2.0941 -7.6044,-2.0941c-7.6178,0 -13.897,5.7395 -14.7512,13.1284c2.2332,-6.9868 8.7795,-12.0479 16.5063,-12.0479c2.0525,0 4.0218,0.358 5.8493,1.0136zm12.3278,24.9666l0,24.4853l-34.5405,0c3.8076,-2.117 6.6453,-1.9014 11.3452,-1.7528c6.4003,0.2024 13.4724,-2.4788 16.9505,-6.029c3.4785,-3.5506 -0.3148,-0.8401 -4.2524,0.1588c-3.9382,0.9983 -11.5585,1.1046 -16.6522,-0.2343c16.043,0.2187 22.2867,-4.9709 25.8324,-9.6186c3.5455,-4.6476 -1.5335,-0.8069 -4.8238,0.7953c-3.2901,1.6037 -9.0284,2.7494 -15.3383,1.9139c9.5512,-0.0198 16.8185,-4.7928 21.4791,-9.7186z" fill="#626262"/></svg>
+ sks-keyservers.net</a -->
+ </div>
+ </section>
+ <section>
+ <h2 id="contact">Contact</h2>
+ <div class="box-of-links">
+ <a href="mailto:mike@php.net"
+ class="email"
+ ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="4.60rem" height="4rem" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 512 448"><path d="M469 21H43q-18 0-30.5 13T0 64v256q0 17 12.5 30T43 363h426q18 0 30.5-13t12.5-30V64q0-17-12.5-30T469 21zm-40 43L256 166L83 64h346zM43 320V90l202 121q2 2 11 2t11-2L469 90v230H43z" fill="#626262"/></svg></a>
+ <a href="irc://chat.freenode.net/m6w6,isnick" class="irc"
+ ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="4rem" height="4rem" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path opacity=".3" d="M20 4H4v13.17L5.17 16H20V4zm-6 10H6v-2h8v2zm4-3H6V9h12v2zm0-3H6V6h12v2z" fill="#626262"/><path d="M20 18c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14zm-16-.83V4h16v12H5.17L4 17.17zM6 12h8v2H6zm0-3h12v2H6zm0-3h12v2H6z" fill="#626262"/></svg>
+ m6w6@freenode</a>
+ <a href="irc://irc.efnet.info/m6w6,isnick" class="irc"
+ ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="4rem" height="4rem" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 4h16v12H5.17L4 17.17V4m0-2c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2H4zm2 10h8v2H6v-2zm0-3h12v2H6V9zm0-3h12v2H6V6z" fill="#626262"/></svg>
+ m6w6@efnet</a>
+ <!-- a href="skype:live:m6w6_1" class="skype"
+ ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="3.84rem" height="4rem" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 464 488"><path d="M441 267q3-15 3-33q0-88-63-151T230 20q-16 0-33 3q-32-19-68-19q-53 0-91 37.5T0 133q0 36 19 68q-2 11-2 33q0 89 62.5 151.5T230 448q18 0 34-3q30 19 68 19q53 0 91-37.5t38-91.5q0-37-20-68zm-109 64q-13 18-40 31q-27 11-62 11q-43 0-70-15q-20-11-32-29q-13-17-13-36q0-9 8-17q7-7 19-7q9 0 16 5q7 6 12 17q4 10 11 21q7 8 18 14q12 5 30 5q25 0 41-11q16-10 16-27q0-11-8-21q-10-8-23-12t-36-9q-33-8-52-16q-21-9-34-25q-12-16-12-39t13-40q14-18 38-26q23-10 58-10q26 0 46 6q20 8 32 17q13 10 19 21q6 12 6 22t-8 18q-7 8-19 8q-11 0-16-5q-6-6-11-15q-8-16-19-23q-9-8-34-8q-22 0-36 9q-13 9-13 21q0 8 4 13q4 6 13 10q7 4 16 6q5 2 28 7q27 7 44 12q18 6 34 15q14 11 22 24q7 13 7 34q0 25-13 44z" fill="#626262"/></svg>
+ m6w6@skype</a -->
+ <a href="xmpp:m6w6@jabber.ccc.de"
+ class="jabber"
+ ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="4rem" height="4rem" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M12 15.4C9.75 13.09 8 9.54 8 6L2 4c0 5.65 4.33 10.11 8.55 12.66C9.38 17.5 8.15 18 7 18v1c1.2 0 3.03-.54 5-1.54c1.97 1 3.8 1.54 5 1.54v-1c-1.15 0-2.38-.5-3.55-1.34C17.66 14.11 22 9.65 22 4l-6 2c0 3.54-1.75 7.09-4 9.4z" fill="#626262"/></svg></a>
+ </div>
+ </section>
+ <section>
+ <h2>Social</h2>
+ <div class="box-of-links">
+ <!-- a href="https://about.me/m6w6" rel="external" class="about-me"
+ ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="2em" height="2em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M19.536 9.15c-1.373 0-2.133 1.014-2.294 2.116h4.608c-.125-1.05-.867-2.115-2.314-2.115m-2.26 3.617c.235 1.156 1.193 1.97 2.532 1.97c.725 0 1.77-.27 2.384-.914l1.175 1.35c-1.064 1.11-2.653 1.426-3.74 1.426c-2.64 0-4.697-1.906-4.697-4.606c0-2.535 1.894-4.62 4.57-4.62c2.585 0 4.5 1.98 4.5 4.604v.766h-6.723v.023zm-6.487 3.83v-5.69c0-.976-.435-1.536-1.338-1.536c-.814 0-1.355.585-1.717 1.007v6.24h-2.35v-5.7c0-.976-.415-1.532-1.318-1.532c-.813 0-1.375.586-1.717 1.006v6.24H0V7.508h2.35v1.15c.4-.464 1.302-1.26 2.71-1.26c1.247 0 2.096.525 2.477 1.59c.524-.762 1.5-1.59 2.91-1.59c1.7 0 2.69 1.01 2.69 2.962v6.24h-2.353l.005-.006z" fill="#626262"/></svg>
+ About</a -->
+ <a href="https://twitter.com/_m6w6" rel="external" class="twitter-com"
+ ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="2.08em" height="2em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 464 448"><path d="M410 174q40-3 50-29q-8 5-24 7.5t-30-1.5q-2-8-2-11q-10-35-38-57.5T306 64q3-2 11-4l9-2q10-3 15.5-7t3.5-8q-1-2-5.5-2T329 42.5T317.5 46l-11 4l-6.5 2q23-8 25-19q-21 3-36 17q6-8 7-13q-40 25-73 111q-22-22-34-28q-46-26-119-52q-2 36 40 58q-8-1-29 3q7 36 52 46q-20 1-32 13q18 32 57 27q-25 12-16.5 27.5T173 255q-37 37-88 37T2 259q42 57 107 78.5t125.5 9.5T344 295.5t63-95.5q36 1 55-20q-31 4-52-6z" fill="#626262"/></svg>
+ Twitter</a>
+ <!-- a href="https://flattr.com/profile/m6w6" rel="external" class="flattr-com"
+ ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="2em" height="2em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M1.906 12C1.906 6.432 6.432 1.906 12 1.906c.048 0 4.003 0 5.455.002L14.53 4.834l1.344 1.344L21.903 0H12C5.373 0 0 5.373 0 12v9.331l1.91-1.759v-.096c-.002-.244-.004-7.404-.004-7.476zM24 2.668l-1.91 1.76v.096L22.093 12c0 5.568-4.528 10.094-10.093 10.094c-.048 0-4.003 0-5.455-.002l2.925-2.926l-1.344-1.344L2.097 24H12c6.627 0 12-5.373 12-12V2.668z" fill="#626262"/></svg>
+ Flattr</a -->
+ <!-- a href="https://www.openhub.net/accounts/mike" rel="external" class="openhub-net"
+ ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="2em" height="2em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 96 96"><g transform="translate(0.000000,96.000000) scale(0.100000,-0.100000)" fill="none"><path d="M0 480 l0 -480 480 0 480 0 0 480 0 480 -480 0 -480 0 0 -480z m368 169 c152 -74 126 -315 -39 -359 -142 -38 -277 97 -239 239 13 49 62 109 105 127 46 20 122 17 173 -7z m216 5 c12 -11 16 -35 16 -85 l0 -69 90 0 90 0 0 69 c0 88 22 115 74 95 20 -8 21 -43 1 -50 -12 -5 -15 -31 -15 -144 0 -151 -3 -170 -30 -170 -24 0 -30 19 -30 91 l0 59 -90 0 -90 0 0 -62 c0 -71 -9 -92 -36 -86 -17 3 -19 16 -22 153 -2 119 -6 151 -17 158 -18 10 -20 43 -2 50 24 10 46 7 61 -9z" fill="#626262"/><path d="M245 613 c-110 -29 -131 -193 -32 -253 117 -72 249 79 172 196 -28 43 -92 69 -140 57z" fill="#626262"/></g></svg>
+ Openhub</a -->
+ <a href="https://github.com/m6w6" rel="external" class="github-com"
+ ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="2.08em" height="2em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 464 448"><path d="M338 13q12 29 4 53q18 15 24 47t-3 62q11 1 32.5 1.5t38 2T462 184q-67-8-88-7q-14 5-15 8q73 6 102 16q-77-13-102-14q-22 43-87 48q1 3 7.5 11.5T287 264t-.5 40.5T290 338q2 4 7 8t7 7q-8 8-22 1.5T266 338q-2-8 0-38t-6-32q0 4-2 40t3 39q1 3 5 8.5t3 10.5q-22 2-28.5-13t-6-46.5T233 264q-4 1-4 16q0 5 .5 16.5t.5 18t-1 16.5t-3 15.5t-6 11t-10 7.5t-15 1q-1-5 3-10.5t5-7.5q5-8 3-38.5t0-41.5q-9 6-7 33.5t-2 41.5q-4 9-15.5 12.5T160 355q1-5 7-9t8-8q4-1 2.5-20.5T177 292q-46 9-63-19q-1-3-5-12t-8-14q-2-2-9-7t-9-11q19-5 37.5 16.5T154 268q6 0 24-6q5-18 16-26q-70-11-89-49q-55 3-102 15q31-12 101-16q-1-4-3.5-6t-6.5-2.5t-7.5-1t-9 0t-7.5.5q-38 2-68 7q22-8 96-8q-9-24-4.5-58T115 70q-5-13-4-30t8-27q26 1 58 23q33-8 69-7q5 0 16.5 3t16.5 2t15-7t11-7q15-7 33-7z" fill="#626262"/></svg>
+ Github</a>
+ <a href="https://m6w6.smugmug.com" rel="external" class="smugmug-com"
+ ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="1.92em" height="2em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 464 488"><path d="M188 36q0 14-13 24.5T143 71q-18 0-31-10.5T99 36t13-24t31-10q19 0 32 10t13 24zM344 2q-19 0-32 10t-13 24t13 24.5T344 71q18 0 31-10.5T388 36t-13-24t-31-10zm118 175q0 13-9 43t-30.5 72t-51.5 79.5t-78 64T190 462q-69 0-114.5-30.5t-60.5-76t-12-96T27 165q5-10 10.5-16.5T46 141l3-1h381q4 0 9 1.5t14 11t9 24.5zm-46 9H67q-19 38-21 84t20 88q34 58 124 58q42 0 79.5-20t61.5-47.5t43.5-62T403 228t13-42z" fill="#626262"/></svg>
+ SmugMug</a>
+ </div>
+ <h2 id="blog">Blog — <a href="blog/">Mike's sudden Inspirations</a></h2>
+ <ul>
+ {% assign m6w6_posts = site.posts | where: "author", "m6w6" | slice: 0, 3 %}
+ {% for post in m6w6_posts %}
+ <li><small><a href=".{{ post.url }}">{{ post.title }}</a>
+ — posted {{ post.date | date_to_long_string: "ordinal" }}</small></li>
+ {% endfor %}
+ </ul>
+ </section>
+ <section>
+ <h2 id="career">Career</h2>
+ <table class="career-table">
+ <tr class="career-current">
+ {% assign Y = "now" | date: "%Y" %}
+ {% assign rowspan = Y | minus: 2013 | plus: 1 %}
+ <th>{{ Y }}</th>
+ <td rowspan="{{ rowspan }}"><a href="https://www.smugmug.com" rel="external">SmugMug Inc.</a></td>
+ <td rowspan="{{ rowspan }}">Sorcerer</td>
+ <td rowspan="{{ rowspan }}">Remote</td>
+ <td></td>
+ </tr>
+ {% assign last_Y = Y | minus: 1 %}
+ {% for y in (2014..last_Y) reversed %}
+ <tr><th>{{ y }}</th></tr>
+ {% endfor %}
+ <tr class="career-change"><th rowspan="2">2013</th></tr>
+ <tr>
+ <td rowspan="7">INQNET</td>
+ <td rowspan="7">Software Developer</td>
+ <td rowspan="7">Vienna</td>
+ <td></td>
+ </tr>
+ <tr><th>2012</th></tr>
+ <tr><th>2011</th></tr>
+ <tr><th>2010</th></tr>
+ <tr><th>2009</th></tr>
+ <tr><th>2008</th></tr>
+ <tr class="career-change"><th rowspan="2">2007</th></tr>
+ <tr>
+ <td rowspan="6">IWORKS</td>
+ <td rowspan="6">Freelancer</td>
+ <td rowspan="6">Remote</td>
+ <td></td>
+ </tr>
+ <tr><th>2006</th></tr>
+ <tr><th>2005</th></tr>
+ <tr><th>2004</th></tr>
+ <tr><th>2003</th></tr>
+ <tr class="career-start"><th>2002</th></tr>
+ </table>
+ </section>
+ <section>
+ <h2 id="opensource">Open source</h2>
+ <table class="opensource-table">
+ <tr>
+ <th>libmemcached</th>
+ <td>C/C++ library for <code>memcached(1)</code> (resurrected)</td>
+ <td>
+ <a href="https://github.com/m6w6/libmemcached" rel="external"
+ >Github</a>,
+ <a href="https://git.m6w6.name/?p=m6w6/libmemcached" rel="external"
+ >Mirror</a>,
+ <a href="https://m6w6.github.io/libmemcached" rel="external"
+ >Docs</a>,
+ <a href="https://artifacts.m6w6.name/libmemcached/" rel="external"
+ >Artifacts</a>
+ </td>
+ </tr>
+ <!-- tr>
+ <th>pecl/psi</th>
+ <td>PHP System Interface</td>
+ <td>
+ <a href="https://github.com/m6w6/ext-psi" rel="external"
+ >Github</a>,
+ <a href="https://git.m6w6.name/?p=m6w6/ext-psi" rel="external"
+ >Mirror</a>,
+ <a href="http://pecl.php.net/package/psi" rel="external"
+ >PECL</a>,
+ <a href="https://mdref.m6w6.name/psi" rel="external"
+ >Docs</a>
+ </td>
+ </tr -->
+ <tr>
+ <th>pecl/http</th>
+ <td>PHP HTTP Extension</td>
+ <td>
+ <a href="https://github.com/m6w6/ext-http" rel="external"
+ >Github</a>,
+ <a href="https://git.m6w6.name/?p=m6w6/ext-http" rel="external"
+ >Mirror</a>,
+ <a href="http://pecl.php.net/package/pecl_http" rel="external"
+ >PECL</a>,
+ <a href="https://mdref.m6w6.name/http" rel="external"
+ >Docs</a>
+ </td>
+ </tr>
+ <tr>
+ <th>pecl/pq</th>
+ <td>PHP PostgreSQL Extension</td>
+ <td>
+ <a href="https://github.com/m6w6/ext-pq" rel="external"
+ >Github</a>,
+ <a href="https://git.m6w6.name/?p=m6w6/ext-pq" rel="external"
+ >Mirror</a>,
+ <a href="http://pecl.php.net/package/pq" rel="external"
+ >PECL</a>,
+ <a href="https://mdref.m6w6.name/pq" rel="external"
+ >Docs</a>
+ </td>
+ </tr>
+ <tr>
+ <th>pharext</th>
+ <td>PHP Extension Installer</td>
+ <td>
+ <a href="https://github.com/pharext/pharext" rel="external"
+ >Github</a>,
+ <a href="https://git.m6w6.name/?p=pharext/pharext" rel="external"
+ >Mirror</a>,
+ <a href="https://pharext.org" rel="external"
+ >Website</a>
+ </td>
+ </tr>
+ </table>
+ </section>
--- /dev/null
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2
+
+mQENBFDcYVsBCADZmu3ac2q1H+Tz8S3XrNQGs+TBHRBpEsafPQBn6wpdMdJ/GDeS
+YxwoItoyjLWmg8cc45SWLYHzU3gkcSgljoivYnwbLbEZnCqE1V//oQYaMIAcQvO6
+nnGHWcFN6WyRl6wl3K866fYmwzE+H2JymjIY0YBdV7/oXDRUNrGaF7C7XAjY13sI
+0Uq8BV/q6J3e0xTQw+VAaf6X7mQvQjIgNipTe44ozVPEJSfNpUzPn2uV8ancWru6
+dmtm3fZZkGUcxNhXsVsEX7R1iHNWBuXSqsKmi5KViWbajg6juha/rbQd2b05PxJG
+H6ctGyMeU9ubJqIoVBpHeGyuGaizcv98686NABEBAAG0JU1pY2hhZWwgV2FsbG5l
+ciAobTZ3NikgPG1pa2VAcGhwLm5ldD6JATcEEwEIACEFAla0mo8CGwMFCwkIBwIG
+FQgJCgsCBBYCAwECHgECF4AACgkQSA4+FLCkx8dRVAf/a1POvRGQnpIjhB6AplnF
+Ux3GaIUlrTiUkZMyhftfk7Wgr3b+X4UitoVTaBm6Zsd8wPCwL2T5fD1B3QBq6N+G
+RscCzOq87Co6ZmrLApBTqv89MvF8sCGGuXhKpAClLbe9Un9GFunbrnJk21Q6AqJV
+eIFSYPQ/LmPaAJ3oFifdPyI8W8OFB5GnkH7JImvFr/vH90zm0rt5hSwdpuV5Pxxb
+cCZkAuVw/8OZ+ZupWBqwo9keLTzaGuzLNtruP62OXuwKuaryw80eWfZn5SxI41NV
+joSLfDeoBdFarFtQFJUyEEXpuA4LED/aYxKbvTIZxTn/zC2mrheKn5iLKmJQjVCz
+69HMO8w5ARAAAQEAAAAAAAAAAAAAAAD/2P/gABBKRklGAAEBAAABAAEAAP/bAEMA
+CAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicgIiwjHBwoNyks
+MDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIy
+MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAJkAdAMB
+IgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAAC
+AQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQz
+YnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpz
+dHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbH
+yMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEB
+AAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEG
+EkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6
+Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeY
+mZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery
+8/T19vf4+fr/2gAMAwEAAhEDEQA/AMhtKhfcUAVhzuXiqsmn+dFhx0PJragi8tRu
+fORRJCz/ACoOD1oA5ySB4YxsIBJwKdp1xe2V0GjU5YjoeDWhdWpDAFSCO4plsga4
+O3kDj8aAO2tfEd/5CKCqvtwSRn8qDrGobt32lifTAxWTaggfMvT1qzkYOaAOm0rx
+KJJBDe4Rzwsg6H6+ldEBk5B4NeZko3VhXQ6Jr3k7ba6fMfRZD29jQB1h96TODim7
+1cAqQQe4NOTuaAEIBPIppA52nmnkjnNKAPoaAK4I5zkEHFUtS0yHUogrlkdeUdT0
+NaZUHrzUR2qcjIycYNAHj3iGx8SrqZSTTxdFECiaNPvjJxn3or2AjJ6fnRQB5Ek5
+83yz1AzV5JABWXu/0uRh6AVJLdCKMkmgCzd3iQxnABY8DPrUNjFsUuwyTyapwRvc
+yCV+B2FbNvF8nTmgCcSrGm7tVGe7eViqYGOvoBUeoSC0gaQknn9ayraC9v3GYnSI
+nJJ4zQBcmu4Yl3Sz9OwqvFr0SzBIX3EdV9a0otFt42G9IxxyDyTVqKCzjbMcChh3
+xQBraTrFzAiyxMQhGfLccV1mm6zDekgsUlPPlt/Q964AzPvwBxV6At5atkh16GgD
+0XduOD1prDB4NYmi6wJ8W1wcTfwt/e/+vW7xkYoAb8xlGCNuOQRzmgx/MWJP07VI
+AOfWo1lBlMZPzAZ/CgBNoPUD8aKeRz2ooA8M84B5Wz1Y1DFm6m5+6OlZ73JFsr5+
+9z+daOnNhFIxzQBrRRHCgda1oEKr93OetUbVhnJ61qRuOKAKc0cLOHZAzL0z2pgl
+Zu2K0mijkOSoB9RUTWyg/LQBnne2G9O5qaMhnCBck9T6VWur9La5MbrwvSq76oGc
+CMbR14oA3jbRRD5xzjqaSGVXJVT0qhFdPcp8zEnHU1JbMlvK5Y8EUAXHYqQynDDk
+Edq7DRdTGoWnzn96nD/415/d6nbW4zLPGgP95sVZ0DXrSLU4miuo2VztYK45BoA9
+Kzg5UZpVIJJH601GBXcDSnn64oAUnmik3AcGigD5kluP3UCZ9K3NOnUgA81ysb75
+oh221q2Mvl3QRj9KAO1hfkFfyrRikz7dqw4ZdyAhuauRSOMfzoA3IwWAxT9rjvVC
+3uynJIxWFr3jm10tjFGPOn/uKeB9TQBu3+nQXQ3udrDvWLJaxw/KrA159qPjTWb9
+iBcGCM/wx8frWUuraiJA4vJiw/vOTQB69asUOM8VmeKr+ay08PCcSM20VieGvEpu
+bpLa9cK7cK3Yn+lbfiqD7Zaw+SwcxtkheaAPL5bme4lMk0jO56ljmrFpeyQOCGIx
+TpdMuFlcxwSPHnghT0oGn3JwPK2E/wB9gD+VAHq/g/x5cWqRJdu09rjDA8sn09R7
+V61b3MN5AtxbSrJG4BBU5r5o0y0vLV0IKspI+Ugj+de8eC9EbQ9HkeZ8yXT+a6rn
+amQOAKAOi/SilCDHIJ96KAPl5dNvIYVu5I9sQOAT71dwCUdfvCtCcz31sYFY4YdB
+0rGhlKkxOMMpwRQB0VpOdqk9q00m3YYHFYdjJuI54rXCb0+TPSgDM1/xIdMtjHCE
+eaUFACfucfex+PFedO7OxZmJJOSTWhrW+TUZ92c54zWaiknHU+lABUiKSa1tK8O3
+WoygbTGnc4yfyro4NEs9LkVZCZJR1C8kfj2/CgDE0nw9d3sy5Ro04O7v+VeuWWlS
+SWyLO+1AoG2MYz9TWXpzwrGEhj2g88CumhcpEN55xQBRPhywMbKEPzdRnrWPe+EI
+GOYWC10rS8kg1CZcHk0AcvB4XjtMu8hZu3pXqeh3aTaZAqHlFCkH2rkHkEgwATTt
+LvX0/UYDn92zhXHseM0Aehb17/zoqE8npRQB876Oz3mnxus7LtYAgdjVfVrGeHfc
+OnIP+sXow96l0awmsZZUSQPFIPlz1DCtW+aK801wzlGPDD3oA5/S79GkClsenvW/
+e6tHp2nNKCDKflRfUmvPPMksr1sH7jfnXR6akuoXEd3cjKIP3aH+dADZtOub+ITX
+axrKwyAqYIq3pug28JEjr5j+/FbiRCTG7tVuKFFP3aAGQFgPJTbFH6IMVq2ek2p+
+YkMe+etQRogPIq9DLGhG1ST7CgDSgghhXCIop0jYIxwPWoo2lk+7Hj3JxUiwD70r
+bj6DpQAqL5rZz8vr608xKOi/nS+YAOKjaXrQAjqAOWA9hVG5IZSq8Ejg+9Ts4z3/
+ABqvK2TQBbf4nWtkkUEtpLLKqAOwI+93ornG0OWeR5I7ZnVmJBCZ70UActb3LRyB
+8n5TWbrWqq7yLGSuefxq0TtkYH1rD1qFlk87Hyk4zQBmks8gYnP1rrNG1SFIVhkj
+ZSOh7VySN3zWnp0xMi56UAeg2zxyqGVsg1bBI4ArIsXUopXGO4q88gyPmIoA0YpZ
+F42g1ZWSRh90D8ayo5M/xmrMT88scUAa8Mki8GQAe1WGlGODWWki445qcSA8daAL
+AlLE0pJ4qv5qocmmNfIG25+lAFhyvXNVZG75qvdXqiPINUhfoULFh7c0Ad9oWjPq
+WlpcQXkkSliCqnjINFaPw+dP+EUiZnXJkc9feigDwm9t9q78Hjqax7xRNAyMcgjg
++hrpXAmhKAbWPUE/yrlroGKV0OeO9AGFyjFT2q1ZTeW+Qear3I/eEio43KkUAd1o
+98rpsYcg1qyzBSCe9cBaai8Dhh2robfWxPhXwaAOiSZCODU0c/bpWMs6/eBytTx3
+CNnDc0AbiXHuKl+1qFPzYrA+1qvVsVHPqaohAYHtQBqTX5YMEfNUV1Bmb5m+YDjN
+YbaiyZCncc5qpJekNvBOQ1AGzf6ocABjwKzHvppJoYoictwceuazp7sH77ZOcgCu
+l8F6cL7VPtk52JFyinuaAPSdKjl07TILZWcbF5we/eipcN2ciigDzs7CpyOaydVt
+d8e9Vyf7wrcDxyJtcbT69qiltXCZTDr14oA8/kGJgDUcsO07h93+VbWs2JSTzUTH
+cjFUUwy/WgCiH4wMUCVgcg4PtVmSzJBeIcdcVTOQeRQBpW2rzQcHke4q9FrSGQMV
+x61z+aUHFAG/NqrOoCdfWqol8z5pZOD2FZqyEUBmPAzQBelnCH5GBwaikut3C9KW
+30u9u3VYoHbccA44rtdI8CLF+8vvnfGVQfdB96AMTw54ffU7iOW4VvJZsKAOW/8A
+rV6M+mpGEDbUK8RzRjBHsRVK1aXTZl+QxlOF44A9q34LiHUIxjAl/u9moAyv7Vu7
+QmG4haR1/jVSQR60VekWSJysciBR2ccj2ooA89tNe066wPM8tz/DJx+tbEaB4w8M
+n5d64647fWup0L/kH/8AAjQBHfq+zEqZHriuUu4RDLlfuk1393/qT9K5q7/1f40A
+ZVspJFXG0yC5HzoAfUcVYh6irkXagDB/4Rxef3+B2+WprPwddXmSs0YUdyDzXR/w
+H6Vs6b/qhQBgWvw+hWINc3LtJ/dQYFdDp/hrSbaNAloGkX+N+STWmPuipIupoAiW
+2SN87QAOwGKnJGMqSKjk60qdBQASQrOhWRN3uOtZZhltpwsZOOoPTFbq1Xm/1ooA
+q7z35Pcn1oqZutFAH//ZiQE3BBMBCAAhBQJWtJr9AhsDBQsJCAcCBhUICQoLAgQW
+AgMBAh4BAheAAAoJEEgOPhSwpMfHlEMH/2RkL13XEBxSLUV+E+KqpWexYb3HQwR7
+Dss8EQ1fBoEuYCqfb7zG1CqYyDKkIobKvg1S47n0abvdffEcdLf8S96oqq1n/CmL
+uKvjvmyHeF0gBMWXIb+YlKixj7Mpc2mufDBonSM51n4W6pFXWpvQhanje6faZSa0
+cgzjTYlQy/E+OAA8STprI9WcLOIlaBHA2YUultojm4cBh222nMPnnSqevjoPwZTz
+LqwPgRj+VcUBGCoX/rqPfJqw7jtIIpXwxLOt4pLG84BoTes+qb/kRDIcU0Wbd9Cn
+LocZEi+Zj5L94YkaXRFNaKKjSwBvy5CmSQWgGN2vHPBjd8gmMwW2qf25AQ0EUNxh
+WwEIAMZln5hJQ7c+yMzjh01pd/7y4odXQEc4CUr+tr9ppEMHG/VMjJjOWQ8mGcN+
+mRaEsq3A8VIqVny5N8IlffnajonQR2lVSfTrm9eRWRNIuMJBzwqJZLxBgq8MVgUi
+0KLmHrfWM3lkfwszg8pVDzQzllqsjgE/tgOvLY20SEAzjSYa6iT2Pg1mYpxHsBPB
+cQBYHIwjxhuddr0z5m4Ozp1hlrNaDkUxXqwDFsjX8WHaYTFWnfG9Li193LFFxfl1
+QkHMBMMX5orgw2FC5qmHA7JG5xtZQwX6RJ4EWSG0OJpdeY4aHHOEr0JzyrTagV+p
+Nz1nf6nY5OSRvF/b2GQ6xtdQXsEAEQEAAYkBHwQYAQIACQUCUNxhWwIbDAAKCRBI
+Dj4UsKTHx7cGCAC4ubC2OxTtqIk4ochy3iV5Xlftrj+vSoKGXYXafDP8DgHOmxq9
+y9sBCpRdZXAiQGQaoJuqz1/BxVoIh/BSICRGkdnnDrfhTS6kdAyl05u/OXaYx8UB
+Thm1TNsyvgbA/V56brd+HfTXF4cjngAYYt3iCVAE1mNtdDsgvbIhBoqQSCtHi52x
+ZWlDrfNy++cp+0w+fC0pof0qdxhhaa5jS/uVq0spdbsu26PtaouJzlopBS99ZWoU
+OGbO90k/Rnk23fsCw6krxw/xj/WfGPIzcPp4gYSji7xRaz+xFE3Iao0d+sT6LH/z
+J6nRE0YmlfXPie+tl+788BWs0gmwGeYfAiC+
+=9TCv
+-----END PGP PUBLIC KEY BLOCK-----
\ No newline at end of file
--- /dev/null
+User-agent: *
+Disallow:
+
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIGajCCBVKgAwIBAgICY38wDQYJKoZIhvcNAQELBQAwgYwxCzAJBgNVBAYTAklM
+MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSswKQYDVQQLEyJTZWN1cmUgRGlnaXRh
+bCBDZXJ0aWZpY2F0ZSBTaWduaW5nMTgwNgYDVQQDEy9TdGFydENvbSBDbGFzcyAy
+IFByaW1hcnkgSW50ZXJtZWRpYXRlIENsaWVudCBDQTAeFw0xNTA0MDMwMTQ2NTNa
+Fw0xNzA0MDIxNDI1MDdaMHUxCzAJBgNVBAYTAkFUMRMwEQYDVQQIEwpCdXJnZW5s
+YW5kMRAwDgYDVQQHEwdOZXVmZWxkMRgwFgYDVQQDEw9NaWNoYWVsIFdhbGxuZXIx
+JTAjBgkqhkiG9w0BCQEWFm1pa2UucGhwLm5ldEBnbWFpbC5jb20wggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyy7CorF7hmBwe97+AutV+8rdMUZ9IEMP8
+n9r3olIomFugyrGj7Un4X5TTNSi6wHZc73Ijlhkbq4ftBBWMP00xfOV+2dpcjxwV
+1Xy/Y1C7QYUGGUpCV70aLc7fozSWDJl3/xK8flAEwYxZlkBdaYByKoewcNjFqDLL
+Wz/yMV4E+cJPcS6VvBiqvRtCvlQPEH6GSQRgwFo0+Ww5IKuQFwLNPPQjfkUDntJG
+BvJKiQJCSTWjhmmGcG4mOvU1d5o0jCdcWQL5W28eIpY9qO2CwUQLUHABoPGKQuh2
+lLPn5s9fbP8SAKcV4I8ldJLxdOlkFk+bYnAk9FDthZ4A6DQ2xx4lAgMBAAGjggLq
+MIIC5jAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHSUEFjAUBggrBgEFBQcD
+AgYIKwYBBQUHAwQwHQYDVR0OBBYEFNGG6lhSx7iAkr/zXFpDmEK8lXWkMB8GA1Ud
+IwQYMBaAFK5Vg2/sMcq59x36r2sx88gd46y7MC8GA1UdEQQoMCaBFm1pa2UucGhw
+Lm5ldEBnbWFpbC5jb22BDG1pa2VAcGhwLm5ldDCCAUwGA1UdIASCAUMwggE/MIIB
+OwYLKwYBBAGBtTcBAgMwggEqMC4GCCsGAQUFBwIBFiJodHRwOi8vd3d3LnN0YXJ0
+c3NsLmNvbS9wb2xpY3kucGRmMIH3BggrBgEFBQcCAjCB6jAnFiBTdGFydENvbSBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTADAgEBGoG+VGhpcyBjZXJ0aWZpY2F0ZSB3
+YXMgaXNzdWVkIGFjY29yZGluZyB0byB0aGUgQ2xhc3MgMiBWYWxpZGF0aW9uIHJl
+cXVpcmVtZW50cyBvZiB0aGUgU3RhcnRDb20gQ0EgcG9saWN5LCByZWxpYW5jZSBv
+bmx5IGZvciB0aGUgaW50ZW5kZWQgcHVycG9zZSBpbiBjb21wbGlhbmNlIG9mIHRo
+ZSByZWx5aW5nIHBhcnR5IG9ibGlnYXRpb25zLjA2BgNVHR8ELzAtMCugKaAnhiVo
+dHRwOi8vY3JsLnN0YXJ0c3NsLmNvbS9jcnR1Mi1jcmwuY3JsMIGOBggrBgEFBQcB
+AQSBgTB/MDkGCCsGAQUFBzABhi1odHRwOi8vb2NzcC5zdGFydHNzbC5jb20vc3Vi
+L2NsYXNzMi9jbGllbnQvY2EwQgYIKwYBBQUHMAKGNmh0dHA6Ly9haWEuc3RhcnRz
+c2wuY29tL2NlcnRzL3N1Yi5jbGFzczIuY2xpZW50LmNhLmNydDAjBgNVHRIEHDAa
+hhhodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS8wDQYJKoZIhvcNAQELBQADggEBAJB3
+kdZlLcR6LMPf+lQt6ITWKh5yZ/A+9lvJJGqnxpVBac/F78ohoHGg5K3HcGDtqEk9
+PvBJykyqg5/v8T/GansHYqyc7W7dAHtAvHV+GXhkgcBtQycldw9qXaJXPLQqzf2s
+Sgju0DZ+sHjI7HJCpGKEqo8rLqGR5rAZr6qWbRLLirksDNrV8Z8MadNdr1qyGciw
+t1fzV3RtozYdOLyCL+r0suOLZX5mAQfQM649e/q8Wym/G9qoHozsFl5PCvwMgJU1
+2WMh8ViRpwT/SipTs8McqgOb0VfTgHSDT3VxuLRzO2Sk7L673LkBGYhP6eZtaX0h
+hfM3+p28/joaf4a29Xk=
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAssuwqKxe4ZgcHve/gLrV
+fvK3TFGfSBDD/J/a96JSKJhboMqxo+1J+F+U0zUousB2XO9yI5YZG6uH7QQVjD9N
+MXzlftnaXI8cFdV8v2NQu0GFBhlKQle9Gi3O36M0lgyZd/8SvH5QBMGMWZZAXWmA
+ciqHsHDYxagyy1s/8jFeBPnCT3EulbwYqr0bQr5UDxB+hkkEYMBaNPlsOSCrkBcC
+zTz0I35FA57SRgbySokCQkk1o4ZphnBuJjr1NXeaNIwnXFkC+VtvHiKWPajtgsFE
+C1BwAaDxikLodpSz5+bPX2z/EgCnFeCPJXSS8XTpZBZPm2JwJPRQ7YWeAOg0Nsce
+JQIDAQAB
+-----END PUBLIC KEY-----