<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:series="http://organizeseries.com/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"> <channel><title>Technik, Gothic und Anderes</title> <link>http://blog.oncode.info</link> <description>Technik ist Spiel, Gothic ist ernst und Zeit hat man zuviel</description> <lastBuildDate>Fri, 25 Jan 2013 11:15:07 +0000</lastBuildDate> <language>de-DE</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.5.1</generator> <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.oncode.info/TechnikGothicUndAnderes" /><feedburner:info uri="technikgothicundanderes" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>47.485073</geo:lat><geo:long>8.333634</geo:long><item><title>Upload und Speichern von Dateien in einer DB mit einer C# ASP.NET MVC Applikation</title><link>http://feeds.oncode.info/~r/TechnikGothicUndAnderes/~3/92SSmOcMFo8/</link> <comments>http://blog.oncode.info/2012/02/01/upload-und-speichern-von-dateien-in-einer-db-mit-einer-c-asp-net-mvc-applikation/#comments</comments> <pubDate>Wed, 01 Feb 2012 17:03:41 +0000</pubDate> <dc:creator>skaldrom</dc:creator> <category><![CDATA[Theorie und Schnipsel]]></category> <category><![CDATA[Webapplikationen]]></category> <category><![CDATA[asp]]></category> <category><![CDATA[asp.net]]></category> <category><![CDATA[bild]]></category> <category><![CDATA[Datenbank]]></category> <category><![CDATA[file]]></category> <category><![CDATA[html5]]></category> <category><![CDATA[mvc]]></category> <category><![CDATA[upload]]></category> <guid isPermaLink="false">http://blog.oncode.info/?p=1917</guid> <description><![CDATA[Hier wird beschrieben, wie man verschiedene Dateitypen (Bilder, Audio, Video, ...) in einer MVC 3 Webapplikation hochladen, in einer Datenbank speichern und auch wieder abspielen kann.]]></description> <content:encoded><![CDATA[<p><img
src="http://blog.oncode.info/wp-content/uploads/2012/02/upload.png" alt="upload" title="upload" width="130" height="155" class="lead" align="left" />MVC mit C# macht ja grunds&#228;tzlich Spass (obwohl f&#252;r einige Leute ja auch Auspeitschen angenehm ist <img
src='http://blog.oncode.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ). Ich habe ein paar spezielle Aufgaben zum Realisieren gefasst und gebe hier ein paar Weisheiten von mir, die wahrscheinlich allgemein bekannt sind und ich einfach nur nicht finden kann.</p><p>In diesem Beitrag wird beschrieben, wie man verschiedene Medien (Bilder, Filme, Audio) hochladen, in einer Datenbank speichern und (mit HTML 5) wieder darstellen kann. Ich gehe aus von einer frisch erstellten und herausgeputzten MVC 3 Webapplikation.</p><p>Am Schluss sollte die Liste in etwa so aussehen:</p><p><a
href="http://blog.oncode.info/wp-content/uploads/2012/02/mediapoc.png"><img
src="http://blog.oncode.info/wp-content/uploads/2012/02/mediapoc-152x300.png" alt="Liste der Medien" title="mediapoc" width="152" height="300" class="alignnone size-medium wp-image-1928" /></a></p><h3>M wie Model</h3><p>Mein Model speichert einen Namen, den Content- (oder MIME-) Type und die bin&#228;ren Daten des Mediums. Aus dem folgenden Model macht das Entity-Framework ein erstaunlich gutes SQL-Schema:<br
/> [cc lang="C#"]<br
/> // Sie ist ein Model und sie sieht gut aus&#8230;<br
/> namespace MediaPOC.Models {<br
/> public class Media {</p><p> public virtual int MediaId { get; set; }<br
/> [Required]<br
/> [StringLength(150)]<br
/> public virtual string Name { get; set; }<br
/> [Required]<br
/> [StringLength(250)]<br
/> [ScaffoldColumn(false)]<br
/> public virtual string MimeType { get; set; }<br
/> [Required]<br
/> public virtual byte[] Data { get; set; }<br
/> }<br
/> }<br
/> [/cc]</p><p>Daraus kann man nun den Rest mal scaffolden. Das Produkt wird aber noch nicht ganz funktionieren, da sich MVC 3 keinen Reim auf das &#8220;Data&#8221; Feld machen kann.</p><h3>V wie View</h3><p>Der grunds&#228;tzliche Trick besteht darin, dem file-upload-Tag einen anderen Namen zu geben um so die Datei ganz kontrolliert im Model abspeichern zu k&#246;nnen. Ebenfalls muss der Form-Tag f&#252;r den Upload angepasst werden. Die wichtigen Teile von <tt>Create.cshtml</tt> (und ev. auch <tt>Edit.cshtml</tt>):<br
/> [cc lang="html"]<br
/> @using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = &#8220;multipart/form-data&#8221; })) {<br
/> @Html.ValidationSummary(true)</p><fieldset><legend>Media</legend><div
class="editor-label"> @Html.LabelFor(model => model.Name)</div><div
class="editor-field"> @Html.EditorFor(model => model.Name)<br
/> @Html.ValidationMessageFor(model => model.Name)</div><div
class="editor-label"> @Html.LabelFor(model => model.Data)</div><div
class="editor-field"> <input
type="file" name="file" /><br
/> @Html.ValidationMessageFor(model => model.Data)</div><p> <input
type="submit" value="Create" /></p></fieldset><p>}<br
/> [/cc]</p><h3>C wie Controller</h3><p>Die Datei wird dem Controller als zus&#228;tzliches Argument &#252;bergeben. Ein Grundproblem ist, dass das Model wegen dem leeren Date ung&#252;ltig ist. Ein Revalidate nach dem Speichern der Daten bes&#228;nftigen die MS-G&#246;tter:<br
/> [cc lang="C#"]<br
/> //<br
/> // POST: /Home/Create</p><p> [HttpPost]<br
/> public ActionResult Create(Media media, HttpPostedFileBase file)<br
/> {<br
/> // Do we have a file<br
/> if (file != null &#038;&#038; file.ContentLength > 0)<br
/> { // Yes<br
/> media.MimeType = file.ContentType;<br
/> media.Data = new byte[file.ContentLength];<br
/> file.InputStream.Read(media.Data, 0, file.ContentLength);<br
/> }<br
/> // If a file was supplied, we have saved the data in teh model<br
/> ModelState.Clear();<br
/> TryValidateModel(media);<br
/> if (ModelState.IsValid)<br
/> {<br
/> db.Media.Add(media);<br
/> db.SaveChanges();<br
/> return RedirectToAction(&#8220;Index&#8221;);<br
/> }</p><p> return View(media);<br
/> }<br
/> [/cc]</p><p>Und das wars schon.</p><h3>Moment, wie kriegen wir die Daten wieder raus?</h3><p>Nun, &#228;&#228;&#228;&#228;hm, ja. Ganz grunds&#228;tzlich braucht es sicher eine M&#246;glichkeit, die Daten dem Browser zu senden. Die folgende L&#246;sung ist einfach und nett, hat allerdings ein Problem: Der Dateiname bei einem Download ist h&#228;sslich.<br
/> [cc lang="C#"]<br
/> namespace MediaPOC.Controllers {<br
/> public class MediaController : Controller {<br
/> private MediaPOCContext db = new MediaPOCContext();</p><p> //<br
/> // GET: /Media/Show/5<br
/> public ActionResult Show(int id) {<br
/> Media media = db.Media.Find(id);<br
/> return File(media.Data, media.MimeType);<br
/> }<br
/> }<br
/> }<br
/> [/cc]</p><p>Um in den Views locker zu bleiben habe ich mir HTML5 zu Hilfe geholt. Ein View-Helper soll jeweils einen korrekten Media-Tag und ein Link darstellen. Bei Audio/Video wird das Element unsichtbar gemacht, bis man sich sicher ist, dass der Browser das Format beherrscht. Das Format des Mediums wird beim Tag in einem <tt>data-type</tt> Attribut gespeichert. Angewendet wird der Tag in einer View mittels:<br
/> [cc lang="HTML"]<br
/> @Html.MediaTag(mediaObject)<br
/> [/cc]</p><p>Ich weiss, der Code ist leicht redundant, aber ich wollte Audio und Video aus irgendeinem ganz wichtigen Grund, den ich vergessen habe, trennen:<br
/> [cc lang="C#"]<br
/> namespace MediaPOC.Helpers {<br
/> public static class HtmlHelpers {<br
/> public static MvcHtmlString MediaTag(this HtmlHelper helper, Media media, int thumbnailsize=50) {<br
/> UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);<br
/> string url = urlHelper.Action(&#8220;Show&#8221;, &#8220;Media&#8221;, new { id = media.MediaId });</p><p> TagBuilder mediaTag;<br
/> TagBuilder brTag= new TagBuilder(&#8220;br&#8221;);</p><p> string tag=&#8221;";</p><p> if(media.MimeType==&#8221;image/png&#8221; || media.MimeType==&#8221;image/gif&#8221; || media.MimeType== &#8220;image/jpeg&#8221;) {<br
/> TagBuilder imageTag = new TagBuilder(&#8220;img&#8221;);<br
/> imageTag.MergeAttribute(&#8220;src&#8221;, url);<br
/> imageTag.MergeAttribute(&#8220;class&#8221;, &#8220;thumbnail&#8221;);</p><p> mediaTag = new TagBuilder(&#8220;a&#8221;);<br
/> mediaTag.MergeAttribute(&#8220;href&#8221;, url);<br
/> mediaTag.InnerHtml = imageTag.ToString();<br
/> tag=mediaTag.ToString(TagRenderMode.Normal);</p><p> }<br
/> else if (media.MimeType.StartsWith(&#8220;audio/&#8221;))<br
/> {</p><p> TagBuilder aTag = new TagBuilder(&#8220;a&#8221;);<br
/> aTag.MergeAttribute(&#8220;href&#8221;, url);<br
/> aTag.InnerHtml = media.Name;</p><p> mediaTag = new TagBuilder(&#8220;audio&#8221;);<br
/> mediaTag.MergeAttribute(&#8220;data-type&#8221;, media.MimeType);<br
/> mediaTag.MergeAttribute(&#8220;style&#8221;, &#8220;display:none&#8221;);<br
/> mediaTag.MergeAttribute(&#8220;class&#8221;, &#8220;thumbnail&#8221;);<br
/> mediaTag.MergeAttribute(&#8220;src&#8221;, url);<br
/> mediaTag.MergeAttribute(&#8220;controls&#8221;, &#8220;controls&#8221;);<br
/> mediaTag.InnerHtml = aTag.ToString();<br
/> tag = mediaTag.ToString(TagRenderMode.Normal) + brTag.ToString()+aTag.ToString();</p><p> }<br
/> else if (media.MimeType.StartsWith(&#8220;video/&#8221;))<br
/> {</p><p> TagBuilder aTag = new TagBuilder(&#8220;a&#8221;);<br
/> aTag.MergeAttribute(&#8220;href&#8221;, url);<br
/> aTag.InnerHtml = media.Name;</p><p> mediaTag = new TagBuilder(&#8220;video&#8221;);<br
/> mediaTag.MergeAttribute(&#8220;data-type&#8221;, media.MimeType);<br
/> mediaTag.MergeAttribute(&#8220;style&#8221;, &#8220;display:none&#8221;);<br
/> mediaTag.MergeAttribute(&#8220;class&#8221;, &#8220;thumbnail&#8221;);</p><p> mediaTag.MergeAttribute(&#8220;src&#8221;, url);<br
/> mediaTag.MergeAttribute(&#8220;controls&#8221;, &#8220;controls&#8221;);<br
/> mediaTag.InnerHtml = aTag.ToString();<br
/> tag = mediaTag.ToString(TagRenderMode.Normal) + brTag.ToString() + aTag.ToString();</p><p> }<br
/> else<br
/> {<br
/> mediaTag = new TagBuilder(&#8220;a&#8221;);<br
/> mediaTag.SetInnerText(media.Name);<br
/> mediaTag.MergeAttribute(&#8220;href&#8221;, url);<br
/> tag = mediaTag.ToString(TagRenderMode.Normal);<br
/> }</p><p> return new MvcHtmlString(tag);<br
/> }<br
/> }//end of class<br
/> }//end of namespace<br
/> [/cc]</p><p>Um die entsprechenden Elemente sichtbar zu machen, wenn der Browser sie beherrscht, muss man noch etwas JavaScript absondern:<br
/> [cc lang="JavaScript"]<br
/> $(function () {<br
/> $(&#8220;audio&#8221;).each(function (index) {</p><p> var audioElement = document.createElement(&#8216;audio&#8217;);<br
/> var canPlayType = audioElement.canPlayType($(this).attr(&#8216;data-type&#8217;));</p><p> if (canPlayType.match(/maybe|probably/i)) {<br
/> $(this).show();<br
/> }</p><p> });<br
/> $(&#8220;video&#8221;).each(function (index) {</p><p> var videoElement = document.createElement(&#8216;video&#8217;);<br
/> var canPlayType = videoElement.canPlayType($(this).attr(&#8216;data-type&#8217;));</p><p> if (canPlayType.match(/maybe|probably/i)) {<br
/> $(this).show();<br
/> }</p><p> });<br
/> });<br
/> [/cc]</p><p>So, das wars. Super.</p> <div class="feedflare">
<a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=92SSmOcMFo8:87_Y72UFrus:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=92SSmOcMFo8:87_Y72UFrus:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=92SSmOcMFo8:87_Y72UFrus:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=92SSmOcMFo8:87_Y72UFrus:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=92SSmOcMFo8:87_Y72UFrus:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=92SSmOcMFo8:87_Y72UFrus:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechnikGothicUndAnderes/~4/92SSmOcMFo8" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.oncode.info/2012/02/01/upload-und-speichern-von-dateien-in-einer-db-mit-einer-c-asp-net-mvc-applikation/feed/</wfw:commentRss> <slash:comments>8</slash:comments> <feedburner:origLink>http://blog.oncode.info/2012/02/01/upload-und-speichern-von-dateien-in-einer-db-mit-einer-c-asp-net-mvc-applikation/</feedburner:origLink></item> <item><title>Programmierquiz: Kürzesten, nicht passenden String finden, auf dass ein RegExp nicht passt</title><link>http://feeds.oncode.info/~r/TechnikGothicUndAnderes/~3/Hoq_OlYGU9Q/</link> <comments>http://blog.oncode.info/2011/10/15/programmierquiz-kurzestes-nicht-passendes-wort-finden-auf-dass-ein-regexp-nicht-passt/#comments</comments> <pubDate>Sat, 15 Oct 2011 10:47:24 +0000</pubDate> <dc:creator>skaldrom</dc:creator> <category><![CDATA[Theorie und Schnipsel]]></category> <category><![CDATA[Aufgaben]]></category> <category><![CDATA[Python]]></category> <category><![CDATA[RegExp]]></category> <category><![CDATA[Regular Expressions]]></category> <guid isPermaLink="false">http://blog.oncode.info/?p=1905</guid> <description><![CDATA[Aufgabe: Finde den k&#252;rzesten String in einem gegebenen Alphabet, auf dass ein gegebener Regular Expression nicht passt.]]></description> <content:encoded><![CDATA[<p>Hier mal eine lustige Aufgabe, mit der ich vor Kurzem konfrontiert war: Gegeben sei ein Alphabet Σ mit Symbolen und eine Regular Expression, wie etwa <tt>(0*|1*)(0*|1*)(0*|1*)</tt>. Nun ist dar k&#252;rzeste String mit Symbolen aus dem Alphabet gesucht, auf dass der gegebene RegExp <em>nicht</em> passt.</p><p>&#8230;Hier w&#252;rde etwas Musik gespielt und ein Countdown eingeblendet werden, damit der interessierte Leser eine L&#246;sung erarbeiten kann <img
src='http://blog.oncode.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> &#8230;</p><p>Meine L&#246;sung funktioniert, sofern die Symbole im Alphabet einem Symbol in UTF-8 entsprechen und ist trivial: Zuerst werden alle Permutationen gebildet und der RegExp daran getestet. Aus reinem Masochismus habe ich versucht, dies in Python 3.2 zu implementieren. Und nein, <em>itertools</em> packt das nicht!</p><p>Ein Testdurchgang k&#246;nnte folgendermassen aussehen (Das Alphabet besteht aus 0 und 1):</p><pre>
$ python3.2 msfr.py -v '(0*|1*)(0*|1*)(0*|1*)' 0 1
Σ: {0, 1}
  Testing: '^(0*|1*)(0*|1*)(0*|1*)$' with ε MATCH
  Testing: '^(0*|1*)(0*|1*)(0*|1*)$' with 0 MATCH
  Testing: '^(0*|1*)(0*|1*)(0*|1*)$' with 1 MATCH
  Testing: '^(0*|1*)(0*|1*)(0*|1*)$' with 00 MATCH
[...]
  Testing: '^(0*|1*)(0*|1*)(0*|1*)$' with 0011 MATCH
  Testing: '^(0*|1*)(0*|1*)(0*|1*)$' with 0100 MATCH
  Testing: '^(0*|1*)(0*|1*)(0*|1*)$' with 0101 NOMATCH
  Testing: '^(0*|1*)(0*|1*)(0*|1*)$' with 0110 MATCH
[...]
  Testing: '^(0*|1*)(0*|1*)(0*|1*)$' with 1010 NOMATCH
  Testing: '^(0*|1*)(0*|1*)(0*|1*)$' with 1011 MATCH
[...]
  Testing: '^(0*|1*)(0*|1*)(0*|1*)$' with 1111 MATCH
Found nonmatching strings with length 4: 0101, 1010
</pre><p>Klappt also nicht schlecht. ε ist &#252;brigens der leere String <img
src='http://blog.oncode.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p><p>Dies ist mein erstes Script in Python &#252;berhaupt. F&#252;r Anregungen und Verbesserungsvorschl&#228;ge bin ich mehr als dankbar:<br
/> [cc lang="python"]<br
/> #!/usr/bin/env python<br
/> &#8221;&#8217;<br
/> Find a minimal non-matching string for a given regular expression and an alphabet.<br
/> Created on Oct 1, 2011</p><p>@author: Skaldrom Y. Sarg<br
/> &#8221;&#8217;<br
/> import argparse<br
/> import re<br
/> import sys</p><p>def allstrings(alphabet, length):<br
/> &#8220;&#8221;"Find the list of all strings of &#8216;alphabet&#8217; of length &#8216;length&#8217;&#8221;"&#8221;</p><p> if length == 0:<br
/> return [""]<br
/> c = []<br
/> for i in range(length): # @UnusedVariable<br
/> c = [[x] + y for x in alphabet for y in c or [[]]]</p><p> return c</p><p>if __name__ == &#8216;__main__&#8217;:<br
/> scriptHelp= &#8220;msfr: Find a minimal non-matching string for a given regular expression and an alphabet.\n\<br
/> \n\<br
/> Example: python3 msfr.py &#8216;(0*|1*)(0*|1*)(0*|1*)&#8217; 0 1&#8243;</p><p> parser = argparse.ArgumentParser(description=scriptHelp, epilog=&#8217;Written by Michael Schneider.&#8217;)<br
/> parser.add_argument(&#8216;-v, &#8211;verbose&#8217;, dest=&#8217;verbose&#8217;, action=&#8217;store_true&#8217;, default=False, help=&#8217;output more verbose&#8217;)<br
/> parser.add_argument(&#8216;-m, &#8211;maxlength&#8217;, dest=&#8217;maxlength&#8217;, default=10, help=&#8217;max number of symbols to test (default: 10)&#8217;)<br
/> parser.add_argument(&#8216;regexp&#8217;, type=str, nargs=1, help=&#8217;the regular expression&#8217;)<br
/> parser.add_argument(&#8216;alphabet&#8217;, metavar=&#8217;S', type=str, nargs=&#8217;+', help=&#8217;a symbol of the alphabet&#8217;)<br
/> args = parser.parse_args()</p><p> # Start<br
/> if(args.verbose):<br
/> print(&#8216;Σ: {&#8216; + &#8220;, &#8220;.join(args.alphabet)+&#8217;}')</p><p> foundNonMatch = []<br
/> for wordlength in range(0, args.maxlength):<br
/> for string in allstrings(args.alphabet, wordlength):<br
/> testString = &#8220;&#8221;.join(string)<br
/> testRegexp = args.regexp[0]<br
/> if args.verbose:<br
/> print(&#8221;  Testing: &#8216;^&#8221; + testRegexp + &#8220;$&#8217; with &#8221; + (testString if len(testString) != 0 else &#8216;ε&#8217;), end=&#8221;")<br
/> try:<br
/> result = re.match(&#8216;^&#8217; + testRegexp + &#8216;$&#8217;, testString)<br
/> except re.error as exc:<br
/> if args.verbose:<br
/> print(&#8220;\n&#8221;)<br
/> print(&#8220;ERROR &#8211; Invalid regexp: &#8221; + str(exc))<br
/> sys.exit(0)</p><p> if(result != None):<br
/> if args.verbose:<br
/> print(&#8221; MATCH&#8221;)<br
/> else:<br
/> foundNonMatch.append(testString)<br
/> if args.verbose:<br
/> print(&#8221; NOMATCH&#8221;)<br
/> if(foundNonMatch):<br
/> break<br
/> if not foundNonMatch:<br
/> print(&#8220;No nonmatching strings found until length &#8221; + args.maxlength + &#8220;.&#8221;)<br
/> else:<br
/> foundStingsLength = str(len(foundNonMatch[0]))<br
/> foundStrings = &#8220;, &#8220;.join(foundNonMatch) if len(foundNonMatch[0]) > 0 else &#8216;ε&#8217;<br
/> print(&#8220;Found nonmatching string&#8221; + (&#8220;s&#8221; if len(foundNonMatch) else &#8220;&#8221;) + &#8221; with length &#8221; + foundStingsLength +&#8221;: &#8221; +foundStrings)<br
/> [/cc]</p> <div class="feedflare">
<a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=Hoq_OlYGU9Q:3dt-t_OxZXY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=Hoq_OlYGU9Q:3dt-t_OxZXY:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=Hoq_OlYGU9Q:3dt-t_OxZXY:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=Hoq_OlYGU9Q:3dt-t_OxZXY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=Hoq_OlYGU9Q:3dt-t_OxZXY:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=Hoq_OlYGU9Q:3dt-t_OxZXY:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechnikGothicUndAnderes/~4/Hoq_OlYGU9Q" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.oncode.info/2011/10/15/programmierquiz-kurzestes-nicht-passendes-wort-finden-auf-dass-ein-regexp-nicht-passt/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://blog.oncode.info/2011/10/15/programmierquiz-kurzestes-nicht-passendes-wort-finden-auf-dass-ein-regexp-nicht-passt/</feedburner:origLink></item> <item><title>Dynamische Mailsignaturen in Apple 10.7 (Lion)</title><link>http://feeds.oncode.info/~r/TechnikGothicUndAnderes/~3/DkdghPSh0rE/</link> <comments>http://blog.oncode.info/2011/10/13/dynamische-mailsignaturen-in-apple-10-7-lion/#comments</comments> <pubDate>Thu, 13 Oct 2011 10:45:38 +0000</pubDate> <dc:creator>skaldrom</dc:creator> <category><![CDATA[Applikationen]]></category> <category><![CDATA[Theorie und Schnipsel]]></category> <category><![CDATA[apple]]></category> <category><![CDATA[applescript]]></category> <category><![CDATA[dynamische signatur]]></category> <category><![CDATA[lion shortcut]]></category> <category><![CDATA[mac]]></category> <category><![CDATA[mai.app]]></category> <category><![CDATA[tastaturkürzel]]></category> <guid isPermaLink="false">http://blog.oncode.info/?p=1880</guid> <description><![CDATA[Auch auf dem Mac kann man dynamische Signaturen f&#252;r Mails benutzen.]]></description> <content:encoded><![CDATA[<p><img
src="http://blog.oncode.info/wp-content/uploads/2011/10/dynmail.png" alt="Dynamisches Mail" title="" width="172" height="136" class="lead" align="left" />Wie man in <a
href="/2008/07/28/dynamische-signatur-e-schrecking-fuer-foren-myspace/">verschiedenen</a>, <a
href="/2006/08/31/sich-andernde-mailsignaturen-mit-fortune/">schon geschriebenen Blogeintr&#228;gen</a> sehen kann, ist es mir ein Anliegen, die Welt mit etwas Dynamik zu versehen, zumindest was Mailsignaturen betrifft. Ja, auch in Mac OSX ist das m&#246;glich!</p><p>Von Haus aus bringt OSX keine M&#246;glichkeit mehr mit, dynamische Signaturen zu erstellen. Entweder, weil es so gedacht war, weil diese Funktion in die Cloud ausgelagert wurde <img
src='http://blog.oncode.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> oder wegen <a
href="https://discussions.apple.com/message/6904290?messageID=6904290#6904290">eines Bugs</a>. Ich habe so ziemlich alles durchprobiert, was <a
href="http://hints.macworld.com/article.php?story=20040503211932363">dieser Artikel &#252;ber fortunes</a> und andere Websites beschrieben haben, doch leider l&#228;uft es nicht &#8211; oder nicht mehr &#8211; so.</p><p>Erkenntnisse:</p><ul><li>AppleScripts m&#246;chten nicht einfach so mit Tastaturk&#252;rzeln versehen werden.</li><li>Das <em>AppleScript Utility</em> gibt es nicht mehr. Um AppleScripts zu aktivieren muss der <em>AppleScript-Editor</em> ge&#246;ffnet werden und das Skriptmen&#252; in den Einstellungen aktiviert werden (siehe Abbildung).</li></ul><div
id="attachment_1889" class="wp-caption alignnone" style="width: 674px"><img
src="http://blog.oncode.info/wp-content/uploads/2011/10/Bildschirmfoto-2011-10-10-um-18.08.01.png" alt="" title="Skript-Men&#252; im neuen AppleScript-Editor" width="664" height="454" class="size-full wp-image-1889" /><p
class="wp-caption-text">Skript-Men&#252; im neuen AppleScript-Editor</p></div><p>Will man doch mittels fortune dynamische Signaturen erzeugen, muss man wie Folgt vorgehen:</p><ol><li>Zuerst braucht man <em>fortune</em>. Dies kann man sich beispielsweise per <a
href="http://www.macports.org/">MacPorts</a> beschaffen. Damit MacPorts l&#228;uft, muss XCode vom AppStore installiert werden.</li><li>Dann sollte man sich eine Zitatsammlung bereit legen, wie im <a
href="/2006/08/31/sich-andernde-mailsignaturen-mit-fortune/">Blogeintrag zu dynamischen Signaturen</a> beschrieben.</li><li>Dann muss man den <em>Automator</em> starten und einen neuen Service erstellen.</li><li>Grundeinstellung: &#8220;Dienst empf&#228;ngt <b>keine Eingabe</b> in <b>Mail.app</b>&#8220;</li><li>Als Aktion <em>AppleScript ausf&#252;hren</em> suchen und einf&#252;gen.</li><li>Das AppleScript:<br
/> [cc lang="AppleScript"]<br
/> on run {input, parameters}</p><p> tell application &#8220;Mail&#8221;<br
/> activate<br
/> make new outgoing message with properties ¬<br
/> {content:do shell script &#8220;/Users/linux/Documents/sigs/psignature-mac&#8221;, visible:true}<br
/> end tell<br
/> return input<br
/> end run<br
/> [/cc]<br
/> Nat&#252;rlich muss der Pfad angepasst werden. <em>psignature-mac</em> ist ein Script mit folgendem Inhalt:<br
/> [cc lang="bash"]<br
/> #! /bin/bash<br
/> echo &#8221;  Viele Gr&#252;sse&#8221;<br
/> echo &#8221;     Skaldrom&#8221;<br
/> echo &#8220;-=-=-=-=-=-=-=-=-&#8221;<br
/> /opt/local/bin/fortune `dirname &#8220;$0&#8243;`/quotes/shorties<br
/> [/cc]<br
/> Dann alles speichern und einen Kaffee trinken oder Kekse backen gehen.</li><li>Um den Tastaturk&#252;rzel festzulegen, muss die <em>Systemeinstellungen</em> ge&#246;ffnet werden. Dort auf <em>Tastatur</em> &rarr; <em>Tastaturkurzbefehle</em> gehen. Der Dienst sollte irgendwo erscheinen und ein Klick auf den leeren Platz rechts davon erm&#246;glicht es, einen Tastaturkurzbefehl einzugeben.<br
/> <img
src="http://blog.oncode.info/wp-content/uploads/2011/10/keyboard.png" alt="" title="keyboard" width="639" height="313" class="alignnone size-full wp-image-1896" /></li><li>Mail &#246;ffnen, Tastaturkurzbefehl (ja, ich mag dieses Wort) dr&#252;cken und sich freuen.</li></ol><p>Es gibt auch eine L&#246;sung f&#252;r existierende Mails:<br
/> [cc lang="AppleScript"]<br
/> on run {input, parameters}</p><p> tell application &#8220;Mail&#8221;<br
/> activate<br
/> get do shell script &#8220;/Users/linux/Documents/sigs/psignature-mac&#8221;<br
/> copy return &#038; the result ¬<br
/> to theFortune</p><p> tell application &#8220;System Events&#8221;<br
/> tell process &#8220;Mail&#8221;<br
/> keystroke theFortune<br
/> end tell<br
/> end tell<br
/> end tell<br
/> return input<br
/> end run<br
/> [/cc]</p> <div class="feedflare">
<a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=DkdghPSh0rE:e6r2c9hPYPQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=DkdghPSh0rE:e6r2c9hPYPQ:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=DkdghPSh0rE:e6r2c9hPYPQ:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=DkdghPSh0rE:e6r2c9hPYPQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=DkdghPSh0rE:e6r2c9hPYPQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=DkdghPSh0rE:e6r2c9hPYPQ:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechnikGothicUndAnderes/~4/DkdghPSh0rE" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.oncode.info/2011/10/13/dynamische-mailsignaturen-in-apple-10-7-lion/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://blog.oncode.info/2011/10/13/dynamische-mailsignaturen-in-apple-10-7-lion/</feedburner:origLink></item> <item><title>Klauen ist auch nicht mehr wie früher…</title><link>http://feeds.oncode.info/~r/TechnikGothicUndAnderes/~3/nBF4VPpm32E/</link> <comments>http://blog.oncode.info/2011/06/02/klauen-ist-auch-nicht-mehr-wie-fruher/#comments</comments> <pubDate>Thu, 02 Jun 2011 09:53:59 +0000</pubDate> <dc:creator>skaldrom</dc:creator> <category><![CDATA[Desktop]]></category> <category><![CDATA[Web]]></category> <category><![CDATA[Android]]></category> <category><![CDATA[antitheft]]></category> <category><![CDATA[diebstahl]]></category> <category><![CDATA[Linux]]></category> <category><![CDATA[theft protection]]></category> <guid isPermaLink="false">http://blog.oncode.info/?p=1844</guid> <description><![CDATA[Theft Protection f&#252;r Laptops und Handys, gratis und einfach.]]></description> <content:encoded><![CDATA[<p><img
src="http://blog.oncode.info/wp-content/uploads/2011/06/theft.png" alt="" title="theft" width="158" height="126" class="lead" align="left" />Das Arsenal an Ger&#228;ten, die ein durchschnittlicher Geek heutzutage mit sich herumschleppt, hat bald den Gegenwert eines kleinen Autos. Wenn fr&#252;her ein Rucksack geklaut wurde (oder, hmm, ehrlich gesagt, zerstreut wie immer &#8220;irgendwo liegen gelassen&#8221; wurde), dann war der Rucksack selbst oftmals das teuerste Ding des ganzen Verlustes. Heutzutage &#8211; mit Laptop, Pad, Phone, &#8230; &#8211; geht ein ganzer Serverraum verloren. Meine Wenigkeit ist so was von Monotasking, dass ich oftmals mit atmen, laufen, verdauen und transpirieren schon an die Grenze komme (darum spreche ich so wenig, weil dann mein Herz aussetzen w&#252;rde!), wie soll ich dann noch an die 1001 Ger&#228;te denken, die ich irgendwie zusammen wischen und mitnehmen sollte? Da ich k&#246;rperlich auch nicht unbedingt einem Standard-Hulk entspreche, muss ich wohl gegen Diebstahl andere Massnahmen ergreifen.</p><p>Vorsorge ist besser als Heulen und Therapie im Nachhinein, darum habe ich jetzt, wo alle Ger&#228;te noch um mich herum sind, ein paar Dinge &#252;berlegt. Ich kann das nicht genug gewichten: Man sollte etwas tun, <strong>bevor</strong> die Ger&#228;te weg sind.</p><h3>Was kann man tun?</h3><p>Gewisse Dinge sind sehr einfach zu realisieren und ersparen viel M&#252;he:</p><dl><dt>Regelm&#228;ssiges Backup</dt><dd>Ok, das wird eh niemand tun, bevor nicht eine Semesterarbeit im den ewigen Datengr&#252;nden verschwindet oder stundenlang Daten wiederabgetippt werden m&#252;ssen. Sobald das aber einmal passiert ist, kann ich <a
href="http://luckybackup.sourceforge.net/">luckyBackup</a> und <a
href="http://www.cis.upenn.edu/~bcpierce/unison/">unison</a> empfehlen. Ein NAS w&#228;re mittlerweile ebenfalls erschwinglich. Wenn man viele Ger&#228;te besitzt, kann man auch Backuppen, indem man die Dateien auf allen Computern ablegt/synchronisiert. F&#252;r Serverbesitzer: Ich habe mittlerweile auch viele Dokumente und nicht nur Quellcode im svn.</dd><dt>Synchronisieren von Daten und Adressen</dt><dd>Oftmals wird der Wert von Terminen und Adressen untersch&#228;tzt. Syncen hilft, egal ob mit Google, <a
href="http://www.memotoo.com/">memotoo</a>, oder sonst was&#8230;</dd><dt>Absichern des Systems</dt><dd>Das hilft auch gegen neugierige Mitmenschen! Bootpasswort, BIOS-Passwort und das Booten von externen Ger&#228;ten unbedingt unterbinden! Wenn die Pladde nicht verschl&#252;sselt ist und ich von einem USB-Stick booten kann, hilft auch ein 42-Zeichen langes Passwort nix!</dd><dt>Installation von Anti Theft Software</dt><dd>Siehe unten.</dd></dl><h3>Anti Theft Software</h3><p>Das Prinzip ist einfach: Eine Software wird auf dem Laptop/Handy installiert, die sich regelm&#228;ssig bei einem Server meldet. Sollte das Ger&#228;t verschwinden, k&#246;nnen zum Einen Standort, Manipulationen und sogar Photos vom Dieb &#252;bertragen, zum Anderen Daten gesichert und das Ger&#228;t fernmanipuliert werden. Der absolute Br&#252;ller und Beweis, dass es klappen kann, ist <a
href="http://thisguyhasmymacbook.tumblr.com/">This Guy Has My MacBook</a>. Der Link ist wirklich hitverd&#228;chtig.</p><p><img
src="http://blog.oncode.info/wp-content/uploads/2011/06/prey-agent.png" alt="" title="prey-agent" width="64" height="64" class="lead" align="left" />F&#252;r Linux-Laptops gibt es beispielsweise <a
href="http://preyproject.com/">Prey</a> (ja, es gibt auch eine Windows- und eine <a
href="https://market.android.com/details?id=com.prey">Android</a>-Version). Diese L&#246;sung ist grunds&#228;tzlich gratis und bei Ubuntu &#252;ber den Package-Manager installierbar. In <tt>/etc/prey/config</tt> muss der api und der device-key von der Website eingetragen werden, dann sollte man noch <tt>/etc/cron.d/prey</tt> &#252;berpr&#252;fen und los gehts. Im Falle eines Diebstahl hat man alle sch&#246;nen Werkzeuge zur Verf&#252;gung.</p><p>Als Administrator kann man unter Linux mittels <tt>/usr/lib/prey/prey.sh</tt> die Ausf&#252;hrung testen, das Logfile befindet sich unter <tt>/var/log/prey.log</tt>. Windows hat in einem Unterverzeichnis <tt>check.bat</tt> das aber nur als Administrator durchl&#228;uft.</p><p>Unter Windows sollte man die Sache sowieso gut austesten, insbesondere, wenn man Standardbenutzer ohne Passwort hat. Diese haben standardm&#228;ssig die Erlaubnis, Dateien zu l&#246;schen. Abhilfe: Vererbbare Rechte f&#252;r das Verzeichnis in normale Rechte umwandeln und den &#8220;Authenticated Users&#8221; das &#8220;Change&#8221; Recht entziehen.</p><p>F&#252;r mein <a
href="/2010/11/25/archos-10-1-ein-geiles-geraet/">nicht-GPS und nicht-3G Android-Pad</a>, steht Prey im Androidmarket leider nicht zur Verf&#252;gung. Irgendeine chinesische Version erscheint zwar als Suchresultat, aber da bin ich nun doch etwas misstrauisch. Funktioniert hat <a
href="https://market.android.com/details?id=com.snuko.android">die App</a> von <a
href="http://www.snuko.com/de">Snuko</a>, wenn man eine Fake-Telefonnummer eingibt.</p><p>So, nun bin ich gespannt wie es sich im Ernstfall bew&#228;hrt. Ich bin auf jeden Fall ger&#252;stet und habe Vorgesorgt!</p><h3>Was w&#228;re sch&#246;n</h3><p>Ganz sch&#246;n w&#228;re eine einfache Bluetooth-Proximity Implementation. Sobald sich die Ger&#228;te mehr als ein paar Meter voneinander entfernen, sollten alle einen schrillen Pfeifton abgeben und eine nette Frauenstimme sollte k&#252;hl aber bestimmt sagen: &#8220;Skaldrom, du seniler Greis, hast Du nicht etwas vergessen?&#8221;. Hmm, das w&#228;re auch f&#252;r Kinder geeignet und in K&#252;rze werde ich auch f&#252;r meine Hosen ein solches Ger&#228;t brauchen&#8230;</p> <div class="feedflare">
<a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=nBF4VPpm32E:zDYvp7-cfps:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=nBF4VPpm32E:zDYvp7-cfps:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=nBF4VPpm32E:zDYvp7-cfps:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=nBF4VPpm32E:zDYvp7-cfps:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=nBF4VPpm32E:zDYvp7-cfps:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=nBF4VPpm32E:zDYvp7-cfps:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechnikGothicUndAnderes/~4/nBF4VPpm32E" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.oncode.info/2011/06/02/klauen-ist-auch-nicht-mehr-wie-fruher/feed/</wfw:commentRss> <slash:comments>1</slash:comments> <feedburner:origLink>http://blog.oncode.info/2011/06/02/klauen-ist-auch-nicht-mehr-wie-fruher/</feedburner:origLink></item> <item><title>Experimentelle Analysen von PHP Code für Enthusiasten</title><link>http://feeds.oncode.info/~r/TechnikGothicUndAnderes/~3/Cw6iln5Mew0/</link> <comments>http://blog.oncode.info/2011/03/07/experimentelle-analysen-von-php-code-fur-enthusiasten/#comments</comments> <pubDate>Mon, 07 Mar 2011 13:57:48 +0000</pubDate> <dc:creator>skaldrom</dc:creator> <category><![CDATA[Theorie und Schnipsel]]></category> <category><![CDATA[Analyse]]></category> <category><![CDATA[Doxygen]]></category> <category><![CDATA[Jenkins]]></category> <category><![CDATA[JSLint]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[php-Lint]]></category> <category><![CDATA[phpcallgraph]]></category> <category><![CDATA[phuml]]></category> <guid isPermaLink="false">http://blog.oncode.info/?p=1790</guid> <description><![CDATA[Weitergehende Tools zur Analyse von PHP-Code.]]></description> <br /> <b>Warning</b>:  Cannot use a scalar value as an array in <b>/home/oncodein/public_html/blogoncodeinfo/wp-content/plugins/organize-series/orgSeries-template-tags.php</b> on line <b>46</b><br /> <br /> <b>Warning</b>:  Invalid argument supplied for foreach() in <b>/home/oncodein/public_html/blogoncodeinfo/wp-content/plugins/organize-series/orgSeries-template-tags.php</b> on line <b>55</b><br /> <content:encoded><![CDATA[<div
class="seriesmeta">Dieser Beitrag ist Teil 2 von 2 in der Serie <a
href="http://blog.oncode.info/series/continuous-integration/" class="series-989" title="Continuous Integration">Continuous Integration</a><ul
class="serieslist-ul"></ul></div><p><img
src="http://blog.oncode.info/wp-content/uploads/2011/03/experiment.png" alt="" title="experiment" height="120" class="lead" align="left" />W&#228;hrend ich im <a
href="/2011/03/02/php-code-analyse-mit-ant/">vorhergehenden Artikel</a> die &#8220;Standardtools&#8221; f&#252;r die Analyse von PHP verwendet habe, m&#246;chte ich hier einen Schritt weitergehen. Wenn ich schon meine Programme analysieren lasse, dann richtig <img
src='http://blog.oncode.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ! Darum hier ein paar nicht-standard Analysetools f&#252;r PHP, die ich als eher experimentell bezeichnen w&#252;rde:</p><ul><li>doxygen</li><li>phuml</li><li>php-lint</li><li>PHP Callgraph</li></ul><h3>Doxygen statt phpDocumentor</h3><p>Ich hab gr&#246;ssten Respekt vor dem <a
href="http://www.phpdoc.org/">phpDocumentor</a> Projekt, aber <a
href="http://www.doxygen.org">Doxygen</a> hat ein paar Vorteile:</p><ul><li>Es kann mit nicht-UTF-8-Dateien umgehen.</li><li>Es ist schneller.</li><li>Es kommt mit anonymen Funktionen klar.</li></ul><p>Leider ist es nicht zu 100% kompatibel zu phpDocumentor. Es hat M&#252;he mit Kurzbeschreibungen, Parametern, etc.</p><p>Die Inbetriebnahme ist ganz einfach: mittels <tt>doxygen -g CONFIGNAME</tt> wird eine Standardkonfiguration erstellt, die man am Besten sofort editiert und mindestens folgende Dinge anpasst:</p><dl><dt>Name des Projekts</dt><dd><tt>PROJECT_NAME = Simple PHP Fixtures System</tt></dd><dt>Ausgabeverzeichnis</dt><dd><tt>OUTPUT_DIRECTORY       = statistics/html/doc/api/</tt></dd><dt>Auch private Members anzeigen</dt><dd><tt>EXTRACT_PRIVATE        = YES</tt></dd><dt>Verzeichnis des zu dokumentierenden Codes</dt><dd><tt>INPUT                  = ../code</tt></dd><dt>SVN-Verzeichnisse nicht durchsuchen</dt><dd><tt>EXCLUDE_PATTERNS       = */.svn/*</tt></dd><dt>Automatische Kurzbeschreibungen</dt><dd><tt>JAVADOC_AUTOBRIEF      = YES</tt></dd></dl><p>Wird der Dokumentationsvorgang nun mittels <tt>doxygen CONFIGNAME</tt> gestartet, so geht es unglaublich schnell und man hat eine peppige API-Dokumentation:</p><p><a
href="http://blog.oncode.info/wp-content/uploads/2011/03/doxygen0.png"><img
src="http://blog.oncode.info/wp-content/uploads/2011/03/doxygen0-300x161.png" alt="" title="doxygen0" width="300" height="161" class="alignnone size-medium wp-image-1813" /></a><a
href="http://blog.oncode.info/wp-content/uploads/2011/03/doxygen1.png"><img
src="http://blog.oncode.info/wp-content/uploads/2011/03/doxygen1-300x161.png" alt="" title="doxygen1" width="300" height="161" class="alignnone size-medium wp-image-1814" /></a></p><p>Das Ant-Target aus dem <a
href="/2011/03/02/php-code-analyse-mit-ant/">letzten Artikel</a> kann folgendermassen umgeschrieben werden:<br
/> [cc lang="xml"]<br
/> <target
name="doc-phpdoc"><br
/> <exec
executable="doxygen" failonerror="false" dir="${basedir}"><br
/> <arg
value="${doxygenconf}"/><br
/> </exec><br
/> </target><br
/> [/cc]</p><p><tt>doxygenconf</tt> muss nat&#252;rlich noch in der properties-Datei mit dem Pfad der Configdatei gef&#252;llt werden.</p><h3>Phuml</h3><p><a
href="http://westhoffswelt.de/projects/phuml.html">phUML</a> erzeugt &#8211; nicht ganz standardkonforme &#8211; UML-Diagramme aus PHP-Code. Je nach Veranlagung sieht man ziemlich schnell, wenn etwas in der Struktur schief gelaufen ist. Wurde das Phuml-SVN ausgecheckt, kann mit dem Kommando <tt>php phuml -r <PFAD_ZUM_CODE> -graphviz -createAssociations true -neato uml.png</tt> ein Diagramm erstellt werden. M&#246;chte man lieber ein anderes Format als ng, so kann das in der Datei <tt>phuml/src/classes/processor/neato.php</tt>, Funktion <tt>execute()</tt> auf der Zeile mit <tt>'neato -Tpng -o [...]</tt> umgestellt werden. Zur Verf&#252;gung stehen viele: ps, pdf, svg, gif, &#8230; <tt>man neato</tt> gibt gerne Auskunft.</p><div
id="attachment_1817" class="wp-caption alignnone" style="width: 310px"><a
href="http://blog.oncode.info/wp-content/uploads/2011/03/uml.png"><img
src="http://blog.oncode.info/wp-content/uploads/2011/03/uml-300x285.png" alt="" title="uml" width="300" height="285" class="size-medium wp-image-1817" /></a><p
class="wp-caption-text">UML-Diagramm</p></div><h3>PHP-Lint</h3><p>Die <a
href="http://de.wikipedia.org/wiki/Lint_%28Programmierwerkzeug%29">Lints</a> haben eine lange Geschichte in der Programmierung, sie sind sozusagen <em>das</em> Werkzeug f&#252;r statische Code-Analyse. Im Gegensatz zu einigen Anderen bin ich der Meinung, dass <tt>php -l</tt> ein Syntaxcheck und damit <em>kein</em> Lint ist. F&#252;r PHP heisst das Teil <a
href="http://www.icosaedro.it/phplint/">PHPLint</a> und ist ebenso kritisch wie die Lints f&#252;r andere Sprachen. Es macht Gebrauch von PHP-Doc Kommentaren f&#252;r erweiterte Analyseinformationen. Leider kann PHP-Lint (im Moment) nicht mit Closures umgehen und etwas speziell ist, dass die verwendeten <a
href="http://www.icosaedro.it/phplint/tutorial.html">PHP-Module</a> zu Beginn der zu untersuchenden Dateien aufgef&#252;hrt werden m&#252;ssen:<br
/> [cc lang="php"]<br
/> /*.<br
/> require_module &#8216;standard&#8217;;<br
/> require_module &#8216;pdo&#8217;;<br
/> require_module &#8216;session&#8217;;<br
/> .*/<br
/> [/cc]</p><p>Ebenfalls kann man ihm mit expliziten castings wie <tt>(string)</tt> oder etwas h&#228;sslichen Kommentaren <tt>/*. string .*/</tt> im Code bei der Arbeit unterst&#252;tzen.</p><p>Die Installation l&#228;uft folgendermassen:</p><ol><li><a
href="http://www.icosaedro.it/phplint/download.html">Download</a> der entsprechenden Version (pure-c f&#252;r Linux).</li><li>Entpacken des Tars und eventuell kompilieren.</li><li>Ein eigenes Verzeichnis erstellen (bspw. <tt>/opt/php/phplint</tt></li><li>Das Verzeichnis <tt>modules</tt> und die Datei <tt>src/phplint</tt> in das erstellte Verzeichnis kopieren.</li><li>phplint starten mittels: <tt>/opt/php/phplint/phplint --modules-path /opt/php/phplint/modules/ <PFAD-ZUR-STARTDATEI-DES-CODES></tt></li><li> Nun sollten ganz viele Fehler ausgegeben werden.<br
/> [cc]<br
/> &#8230;<br
/> /home/skaldrom/svn/syncic/SimplePHPFixturesSystem/trunk/code/SimpleFixtures.php:136: Warning: comparing (mixed) == (mixed): `mixed&#8217; type cannot be compared. Hint: check and convert mixed values to the appropriate type, or consider to use strict comparison operators === or !== if it is the case.<br
/> /home/skaldrom/svn/syncic/SimplePHPFixturesSystem/trunk/code/SimpleFixtures.php:139: notice: &#8216;continue EXPR&#8217;: unadvised programming practice<br
/> /home/skaldrom/svn/syncic/SimplePHPFixturesSystem/trunk/code/SimpleFixtures.php:135: notice: variable `$foreignkey&#8217; assigned but never used<br
/> /home/skaldrom/svn/syncic/SimplePHPFixturesSystem/trunk/code/SimpleFixtures.php:126: notice: variable `$candidateData&#8217; assigned but never used<br
/> /home/skaldrom/svn/syncic/SimplePHPFixturesSystem/trunk/code/SimpleFixtures.php:170: Warning: comparing (mixed) == (string): `mixed&#8217; type cannot be compared. Hint: check and convert mixed values to the appropriate type, or consider to use strict comparison operators === or !== if it is the case.<br
/> /home/skaldrom/svn/syncic/SimplePHPFixturesSystem/trunk/code/SimpleFixtures.php:176: Warning: applying the `[]&#8216; operator to array of undefined index type<br
/> /home/skaldrom/svn/syncic/SimplePHPFixturesSystem/trunk/code/SimpleFixtures.php:178: ERROR: method `SimpleFixtures::_untangleTree()&#8217;: expected return type void, found expression of type array[]string<br
/> /home/skaldrom/svn/syncic/SimplePHPFixturesSystem/trunk/code/SimpleFixtures.php:183: Warning: calling `SimpleFixtures::_untangleTree()&#8217; declared in line 160, argument no. 1: found type `mixed&#8217;, required type `string&#8217;<br
/> /home/skaldrom/svn/syncic/SimplePHPFixturesSystem/trunk/code/SimpleFixtures.php:188: Warning: applying the `[]&#8216; operator to array of undefined index type<br
/> &#8230;<br
/> [/cc]</li></ol><p>Damit phplint auch in <a
href="http://jenkins-ci.org/">Jenkins</a> genutzt werden kann, habe ich einen kleinen Wrapper geschrieben, der die Ausgabe in JSLint-XML umwandelt. Damit kann diese Ausgabe komfortabel beim Violations-Modul eingebaut werden. Die PHP-Datei muss im selben Verzeichnis wie phplint platziert werden und geht davon aus, dass <tt>modules</tt> ein Unterverzeichnis ist. Download hier: <a
href='http://blog.oncode.info/wp-content/uploads/2011/03/phplint.php_.zip'>phplint.php</a>.</p><div
id="attachment_1825" class="wp-caption alignnone" style="width: 310px"><a
href="http://blog.oncode.info/wp-content/uploads/2011/03/phplint-jenkins.png"><img
src="http://blog.oncode.info/wp-content/uploads/2011/03/phplint-jenkins-300x151.png" alt="" title="phplint-jenkins" width="300" height="151" class="size-medium wp-image-1825" /></a><p
class="wp-caption-text">PHPLint in Jenkins</p></div><p>Ein grosses Problem gibt es in Netbeans&#8230; Wird der PHP-Code neu formatiert, werden bei den Kommentaren um die Module herum Leerschl&#228;ge platziert und phplint erkennt sie nimmer. Sehr nervig, echt&#8230;</p><h3>PHP Call Graph</h3><p><a
href="http://phpcallgraph.sourceforge.net/">php CallGraph</a> ist ein wunderbares St&#252;ck Software, dass einige bestehende Libraries clever vereint. Es produziert Aufrufgraphen einer bestehenden Software, die ziemlich effizient mit dem intuitiven Plan des Entwicklers verglichen werden k&#246;nnen. Sch&#246;ne <a
href="http://phpcallgraph.sourceforge.net/examples/">Beispiele</a> gibt es auf der Website.</p><p>phpCallGraph verl&#228;sst sich unter Anderem auf phpDoc-Kommentare. Die sollten also entweder gar nicht oder einigermassen gescheit ausgef&#252;llt werden. Sollte es trotzdem ein Problem geben, so kann zum Debuggen die Zeile 517 und 518 in der Datei <tt>lib/instantsvc/components/CodeAnalyzer/src/code_analyzer.php</tt> entkommentiert werden:<br
/> [cc lang="php"]<br
/> echo &#8216;$filename = &#8216;, var_export($filename, true), &#8220;;\n&#8221;;<br
/> echo &#8216;$result   = &#8216;, var_export($result, true), &#8220;;\n&#8221;;<br
/> [/cc]</p><p>Ich habe einen Patch eingereicht, der einige Warnings entfernt und eine &#8220;ignore&#8221; Option hinzuf&#252;gt, der alsbald angewendet wird.<br
/> <embed
src="/wp-content/uploads/2011/03/callgraph.svg" type="image/svg+xml"></embed></p><h3>Da war ich zu bl&#246;d daf&#252;r</h3><p>F&#252;r <a
href="http://trac2.assembla.com/php-ast">php-ast</a> und <a
href="http://www.program-transformation.org/PHP/PhpSatReleases">php-sat</a> war ich leider zu bl&#246;d. Ich hatte weder Nerven noch Zeit f&#252;r die Build-Prozedur und die Projekte scheinen auch seit l&#228;ngerem still zu liegen. Die Ideen w&#228;ren aber grunds&#228;tzlich interessant.</p> <div class="feedflare">
<a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=Cw6iln5Mew0:bwPhJJD3Gd4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=Cw6iln5Mew0:bwPhJJD3Gd4:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=Cw6iln5Mew0:bwPhJJD3Gd4:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=Cw6iln5Mew0:bwPhJJD3Gd4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=Cw6iln5Mew0:bwPhJJD3Gd4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=Cw6iln5Mew0:bwPhJJD3Gd4:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechnikGothicUndAnderes/~4/Cw6iln5Mew0" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.oncode.info/2011/03/07/experimentelle-analysen-von-php-code-fur-enthusiasten/feed/</wfw:commentRss> <slash:comments>2</slash:comments> <series:name><![CDATA[Continuous Integration]]></series:name> <feedburner:origLink>http://blog.oncode.info/2011/03/07/experimentelle-analysen-von-php-code-fur-enthusiasten/</feedburner:origLink></item> <item><title>PHP Code-Analyse mit Ant</title><link>http://feeds.oncode.info/~r/TechnikGothicUndAnderes/~3/cEjiHwea82I/</link> <comments>http://blog.oncode.info/2011/03/02/php-code-analyse-mit-ant/#comments</comments> <pubDate>Wed, 02 Mar 2011 07:52:41 +0000</pubDate> <dc:creator>skaldrom</dc:creator> <category><![CDATA[Theorie und Schnipsel]]></category> <category><![CDATA[ant]]></category> <category><![CDATA[code analyse]]></category> <category><![CDATA[Coding]]></category> <category><![CDATA[Hudson]]></category> <category><![CDATA[Jenkins]]></category> <category><![CDATA[PEAR]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[Statistik]]></category> <guid isPermaLink="false">http://blog.oncode.info/?p=1772</guid> <description><![CDATA[Mittels ant werden hier einige Statistiken zu bestehenden PHP-Programmen erstellt.]]></description> <br /> <b>Warning</b>:  Cannot use a scalar value as an array in <b>/home/oncodein/public_html/blogoncodeinfo/wp-content/plugins/organize-series/orgSeries-template-tags.php</b> on line <b>46</b><br /> <br /> <b>Warning</b>:  Invalid argument supplied for foreach() in <b>/home/oncodein/public_html/blogoncodeinfo/wp-content/plugins/organize-series/orgSeries-template-tags.php</b> on line <b>55</b><br /> <content:encoded><![CDATA[<div
class="seriesmeta">Dieser Beitrag ist Teil 1 von 2 in der Serie <a
href="http://blog.oncode.info/series/continuous-integration/" class="series-989" title="Continuous Integration">Continuous Integration</a><ul
class="serieslist-ul"></ul></div><p><img
src="http://blog.oncode.info/wp-content/uploads/2011/03/graph.png" alt="Graph Lead" title="graph" width="172" height="136" class="lead" align="left" />Ich mag Code. Nicht jeden nat&#252;rlich, &#8220;Douchebag&#8221; Code nervt, Code der aussieht wie ein schreiender Quasimodo oder Code der von einem Dr. Frankenstein in Ausbildung erstellt wurde sind bemitleidenswert und sehr viel Code stinkt. Code, der gef&#228;llt (wie beispielsweise der von <a
href="http://www.frigidor.ch">Frigidor</a>) ist clever ohne zu bluffen, kurz aber nicht kryptisch, tut etwas, ist lesbar und hat einige Wows drin.</p><p>Diese Bewunderung sollte in Zahlen gefasst werden: mit Statistiken, Diagrammen, Balken und Graphen. Dies dient zur Vorbereitung der &#8220;Continuous Integration&#8221; mit Jenkins/Hudson, die in dieser Serie behandelt wird. Als Quellen haben vor allem <a
href="http://jenkins-php.org/">jenkins-php</a> und ein &#228;usserst Lesbarer Artikel im <a
href="http://entwickler-magazin.de/zonen/magazine/psecom,id,17,ausgabe,428,p,0.html">Entwickler Magazin 01/11</a> gedient.</p><p>Hier wird nun gezeigt, wie mit einem Befehl:</p><ul><li>Die Unittests durchf&#252;hrt.</li><li>Qualitative Softwaremetriken mit <a
href="http://pdepend.org/">PHP Depend</a> misst: Hierarchietiefe, Komplexit&#228;t, &#8230;</li><li>Unsch&#246;ne Teile mit <a
href="http://phpmd.org/">PHPMD</a> identifiziert.</li><li>Copy-Paste-Verbrecher aufsp&#252;hrt mit <a
href="https://github.com/sebastianbergmann/phpcpd">phpcpd</a>.</li><li>Den Coding-Style pr&#252;ft mit dem <a
href="http://pear.php.net/package/PHP_CodeSniffer/redirected">PHP Code Sniffer</a>.</li><li>Quantitative Softwaremetriken mit <a
href="https://github.com/sebastianbergmann/phploc">phploc</a> misst.<li><li>Die <a
href="http://www.phpdoc.org/">PHPDoc</a>-Doku erstellt.</li><li>Die Resultate mit dem <a
href="https://github.com/mayflowergmbh/PHP_CodeBrowser">PHP Code Browser</a> sch&#246;n darstellt.</li></ul><h3>PEAR Tools installieren</h3><p><a
href="http://pear.php.net/">PEAR</a> stellt viele Hilfsprogramme zur Analyse zur Verf&#252;gung. Darum muss zuerst pear und danach diese Tools installiert werden. Am Besten als Root, wenn man nicht ein riesen Chaos verursachen m&#246;chte:<br
/> [cc lang="bash"]<br
/> sudo pear upgrade PEAR<br
/> sudo pear channel-discover pear.pdepend.org<br
/> sudo pear channel-discover pear.phpmd.org<br
/> sudo pear channel-discover pear.phpunit.de<br
/> sudo pear channel-discover components.ez.no<br
/> sudo pear channel-discover pear.symfony-project.com</p><p>sudo pear install Text_Highlighter-0.7.1<br
/> sudo pear install pdepend/PHP_Depend<br
/> sudo pear install phpmd/PHP_PMD<br
/> sudo pear install phpunit/phpcpd<br
/> sudo pear install phpunit/phploc<br
/> sudo pear install PHPDocumentor<br
/> sudo pear install PHP_CodeSniffer<br
/> sudo pear install &#8211;alldeps phpunit/PHP_CodeBrowser<br
/> sudo pear install &#8211;alldeps phpunit/PHPUnit<br
/> [/cc]</p><h3>Ant build Files</h3><p>Um den Build zu steuern, eignet sich <a
href="http://ant.apache.org/">Ant</a> sehr gut. Zwar ist es XML (Anwender sollen kein XML schreiben m&#252;ssen!), stellt aber ein paar vern&#252;nftige Funktionen bereit. F&#252;r einen Build braucht es eine Properties- und eine XML-Datei, die am Besten in ein eigenes <tt>build</tt> Verzeichnis verfrachtet werden. In der Propertiesdatei k&#246;nnen Variablen gesetzt und eventuell auf verschiedene Umgebungen reagiert werden. Bei mir heisst sie <tt>build.properties</tt> und sieht ziemlich einfach aus:<br
/> [cc lang="bash"]<br
/> # Source directory<br
/> source=${basedir}/../htdocs/code<br
/> # Target directory<br
/> builddir=${basedir}/statistics<br
/> # Where are the Unittests<br
/> unittests=${basedir}/tests<br
/> testsuite=suite.php<br
/> # 10: Highest priority, 1: Lowest<br
/> niceness=1<br
/> # Set to a random String if you have no external libraries. PHPCPD accepts only ONE directory<br
/> extlib=inc/external<br
/> phpdocextlib=*${extlib}/*<br
/> extlibs=${extlib},\\.svn<br
/> # Files to consider<br
/> suffixes=php<br
/> # Ruleset for Code Sniffer<br
/> csruleset=${basedir}/conf/syncic<br
/> [/cc]</p><p>Hier sieht man auch schon eines der Hauptprobleme: Die Tools verwenden unterschiedliche Angaben um Verzeichnisse auszuschliessen: Pfade, RegExps, durch Komma getrennt, &#8230; Ziemlich m&#252;hsam.</p><p>Die Build-Datei <tt>build.xml</tt> ist etwas lange, aber gut verst&#228;ndlich. Zuerst werden die abstrakten Ziele eingerichtet und dann gibt es f&#252;r jedes Tool ein Target.</p><p>[cc lang="xml"]<br
/> <?xml version="1.0" encoding="UTF-8" ?></p> <project
name="Easy-Form" basedir="." default="build"> <property
file="build.properties"/> <nice
newpriority="${niceness}"/></p><p> <target
name="build" depends="test, doc" /></p><p> <target
name="clean"><br
/> <delete
dir="${builddir}" /><br
/> </target></p><p> <target
name="prepare" depends="clean"><br
/> <mkdir
dir="${builddir}/logs" /><br
/> <mkdir
dir="${builddir}/logs/coverage" /><br
/> <mkdir
dir="${builddir}/html" /><br
/> <mkdir
dir="${builddir}/html/jdepend" /><br
/> <mkdir
dir="${builddir}/html/unittests" /><br
/> <mkdir
dir="${builddir}/html/experimental" /><br
/> <mkdir
dir="${builddir}/html/doc" /><br
/> <mkdir
dir="${builddir}/html/doc/api" /><br
/> <mkdir
dir="${builddir}/html/doc/codebrowser" /><br
/> </target></p><p> <target
name="test" depends="test-unit, test-static" /></p><p> <target
name="test-static" depends="prepare"></p> <parallel
threadCount="2"> <sequential><br
/> <antcall
target="test-static-jdepend"/><br
/> <antcall
target="test-static-pmd"/><br
/> </sequential><br
/> <antcall
target="test-static-cpd"/><br
/> <antcall
target="test-static-checkstyle"/><br
/> <antcall
target="test-static-phploc"/> </parallel> </target></p><p> <target
name="doc" depends="prepare"><br
/> <sequential><br
/> <antcall
target="doc-phpdoc"/><br
/> <antcall
target="doc-phpcb"/><br
/> </sequential><br
/> </target></p><p> <br
/> <target
name="test-unit" depends="prepare"><br
/> <exec
executable="phpunit" failonerror="true" dir="${unittests}"><br
/> <arg
value="--log-junit" /><br
/> <arg
value="${builddir}/logs/junit.xml" /><br
/> <arg
value="--coverage-clover" /><br
/> <arg
value="${builddir}/logs/coverage/clover.xml" /><br
/> <arg
value="--coverage-html" /><br
/> <arg
value="${builddir}/logs/coverage" /><br
/> <arg
value="--testdox-html" /><br
/> <arg
value="${builddir}/html/unittests/index.html" /><br
/> <arg
value="--configuration" /><br
/> <arg
value="${phpunitconf}" /><br
/> <arg
value="${testsuite}" /><br
/> </exec><br
/> </target></p><p> <br
/> <target
name="test-static-jdepend"><br
/> <exec
executable="pdepend" failonerror="false" dir="${source}"><br
/> <arg
value="--jdepend-xml=${builddir}/logs/jdepend.xml" /><br
/> <arg
value="--jdepend-chart=${builddir}/html/jdepend/dependencies.svg" /><br
/> <arg
value="--overview-pyramid=${builddir}/html/jdepend/pyramid-overview.svg" /><br
/> <arg
value="--summary-xml=${builddir}/logs/jdepend-summary.xml" /><br
/> <arg
value="--phpunit-xml=${builddir}/logs/jdepend-phpunit.xml" /><br
/> <arg
value="--ignore=${extlibs}" /><br
/> <arg
value="--suffix=${suffixes}" /><br
/> <arg
value="${source}" /><br
/> </exec><br
/> </target></p><p> <target
name="test-static-pmd"><br
/> <exec
executable="phpmd" failonerror="false" dir="${source}"><br
/> <arg
value="${source}" /><br
/> <arg
value="xml" /><br
/> <arg
value="codesize,design,naming,unusedcode" /><br
/> <arg
value="--reportfile" /><br
/> <arg
value="${builddir}/logs/pmd.xml" /><br
/> <arg
value="--suffixes" /><br
/> <arg
value="${suffixes}" /><br
/> <arg
value="--exclude" /><br
/> <arg
value="${extlibs}" /><br
/> </exec><br
/> </target></p><p> <target
name="test-static-cpd"><br
/> <exec
executable="phpcpd" failonerror="false" dir="${source}"><br
/> <arg
value="--log-pmd" /><br
/> <arg
value="${builddir}/logs/cpd.xml" /><br
/> <arg
value="--suffixes" /><br
/> <arg
value="${suffixes}" /><br
/> <arg
value="--exclude" /><br
/> <arg
value="${extlib}" /><br
/> <arg
value="${source}" /><br
/> </exec><br
/> </target></p><p> <target
name="test-static-checkstyle"><br
/> <exec
executable="phpcs" failonerror="false" dir="${source}"><br
/> <arg
value="--report=checkstyle" /><br
/> <arg
value="--report-file=${builddir}/logs/checkstyle-result.xml" /><br
/> <arg
value="--extensions=${suffixes}" /><br
/> <arg
value="--ignore=${extlibs}" /><br
/> <arg
value="--standard=${csruleset}" /><br
/> <arg
value="${source}" /><br
/> </exec><br
/> </target></p><p> <target
name="test-static-phploc"><br
/> <exec
executable="phploc" failonerror="false"><br
/> <arg
value="--log-csv" /><br
/> <arg
value="${builddir}/logs/loc.csv" /><br
/> <arg
value="--suffixes" /><br
/> <arg
value="php" /><br
/> <arg
value="--exclude" /><br
/> <arg
value="${extlib}" /><br
/> <arg
value="${source}" /><br
/> </exec><br
/> </target></p><p> <br
/> <target
name="doc-phpdoc"><br
/> <exec
executable="phpdoc" failonerror="false" dir="${source}"><br
/> <arg
value="--directory"/><br
/> <arg
value="${source}" /><br
/> <arg
value="--ignore" /><br
/> <arg
value="${phpdocextlib}" /><br
/> <arg
value="--target" /><br
/> <arg
value="${builddir}/html/doc/api" /><br
/> <arg
value="--output" /><br
/> <arg
value="HTML:frames:earthli" /><br
/> <arg
value="--title" /><br
/> <arg
value="${ant.project.name}" /><br
/> </exec><br
/> </target></p><p> <target
name="doc-phpcb"><br
/> <exec
executable="phpcb" failonerror="false"><br
/> <arg
value="--log"/><br
/> <arg
value="${builddir}/logs" /><br
/> <arg
value="-i" /><br
/> <arg
value="${extlibs}" /><br
/> <arg
value="--output" /><br
/> <arg
value="${builddir}/html/doc/codebrowser" /><br
/> </exec><br
/> </target> </project> [/cc]</p><p>Ist alles richtig eingerichtet, kann der Build mit dem Kommando <tt>ant</tt> gestartet werden.</p><p><b>Hinweis:</b> Das Coverage-XML und das Coverage-HTML m&#252;ssen im gleichen Verzeichnis sein. Wenn der Clover-Report nicht funktioniert und ein 404 not found gibt, liegt es wahrscheinlich daran&#8230;</p><h3>Code Sniffer einrichten</h3><p>Der Stil des Codes (Einr&#252;cken, Benamsung, &#8230;) ist sehr pers&#246;nlich. Sehrwahrscheinlich werden viele Warnungen gezeigt, mit denen man gar nicht einverstanden ist. Das ist aber kein Problem, denn der Codesniffer erlaubt es, eigene Codingstandards zu definieren. mit der neuen Version 1.3 (die mittels <tt>sudo pear install PHP_CodeSniffer-1.3.0RC2</tt> installiert werden kann) geht das ziemlich einfach. Daf&#252;r brauch es in einem Grundverzeichnis eine <tt>ruleset.xml</tt> Datei und in einem Unterverzeichnis <tt>Sniff</tt> die eigenen Regeln, in PHP auscodiert. In <tt>ruleset.xml</tt> kann man sich frei an nestehenden Regeln bedienen. Meines sieht folgendermassen aus:<br
/> [cc lang="xml"]<br
/> <?xml version="1.0"?><br
/> <ruleset
name="Syncic Standard"><br
/> <rule
ref="PEAR"><br
/> <exclude
name="Generic.WhiteSpace.DisallowTabIndent"/><br
/> <exclude
name="PEAR.ControlStructures.ControlSignature"/><br
/> </rule></p><p><rule
ref="Generic.VersionControl.SubversionProperties"/><br
/> <rule
ref="Generic.Classes.DuplicateClassName"/><br
/> <rule
ref="Generic.Strings.UnnecessaryStringConcat"/><br
/> <rule
ref="Generic.PHP.DeprecatedFunctions"/><br
/> <rule
ref="Generic.PHP.ForbiddenFunctions"/><br
/> <rule
ref="Generic.PHP.NoSilencedErrors"/></p><p><rule
ref="PEAR.WhiteSpace.ScopeIndent"></p> <properties> <property
name="indent" value="2"/> </properties> </rule><br
/> </ruleset><br
/> [/cc]</p><p>In dieser Datei &#252;bernehme ich vor allem den PEAR-Standard, konfiguriere etwas herum und mische ein paar allgemeine Regeln hinzu. Vorallem die Indentation mit Spaces wollte ich anpassen. Im <tt>Sniffs</tt> Verzeichnis habe ich meine eigenen Regeln. Beispielsweise <tt>ControlStructures/ControlSignatureSniff.php</tt> (angepasst vom PEAR Coding Standard:<br
/> [cc lang="php"]<br
/> <?php<br
/> /**<br
/> * Verifies that control statements conform to their coding standards.<br
/> */</p><p>if (class_exists(&#8216;PHP_CodeSniffer_Standards_AbstractPatternSniff&#8217;, true) === false) {<br
/> throw new PHP_CodeSniffer_Exception(&#8216;Class PHP_CodeSniffer_Standards_AbstractPatternSniff not found&#8217;);<br
/> }</p><p>/**<br
/> * Verifies that control statements conform to their coding standards.<br
/> */<br
/> class syncic_Sniffs_ControlStructures_ControlSignatureSniff extends PHP_CodeSniffer_Standards_AbstractPatternSniff {<br
/> /**<br
/> * Constructs a PEAR_Sniffs_ControlStructures_ControlSignatureSniff.<br
/> */<br
/> public function __construct() {<br
/> parent::__construct(true);</p><p> }//end __construct()</p><p> /**<br
/> * Returns the patterns that this test wishes to verify.<br
/> *<br
/> * @return array(string)<br
/> */<br
/> protected function getPatterns() {<br
/> return array(<br
/> &#8216;do {EOL&#8230;} while (&#8230;);EOL&#8217;,<br
/> &#8216;while(&#8230;) {EOL&#8217;,<br
/> &#8216;for(&#8230;) {EOL&#8217;,<br
/> &#8216;if(&#8230;) {EOL&#8217;,<br
/> &#8216;foreach(&#8230;) {EOL&#8217;,<br
/> &#8216;} else if(&#8230;) {EOL&#8217;,<br
/> &#8216;} elseif(&#8230;) {EOL&#8217;,<br
/> &#8216;} else {EOL&#8217;,<br
/> &#8216;do {EOL&#8217;,<br
/> );</p><p> }//end getPatterns()<br
/> }//end class<br
/> ?><br
/> [/cc]</p><h3>Was gewinnen wir damit?</h3><p>Nach einem <tt>ant</tt> haben wir zum Einen ganz viele XML-Dateien. In einem sp&#228;teren Beitrag werde ich zeigen, wie diese in ein &#8220;Continuous Integration&#8221; System integriert werden k&#246;nnen. F&#252;r Menscen Lesbar haben wir Folgendes:<br
/> Dokumentation unter <tt>statistics/html/doc/api/</tt>:<br
/><div
id="attachment_1797" class="wp-caption alignnone" style="width: 310px"><a
href="http://blog.oncode.info/wp-content/uploads/2011/03/phpdoc.png"><img
src="http://blog.oncode.info/wp-content/uploads/2011/03/phpdoc-300x166.png" alt="" title="phpdoc" width="300" height="166" class="size-medium wp-image-1797" /></a><p
class="wp-caption-text">PHPDoc Beispiel</p></div><br
/> Eine Liste aller Style-Verst&#246;sse und Chaosattacken unter <tt>statistics/html/doc/codebrowser/</tt>:<br
/><div
id="attachment_1798" class="wp-caption alignnone" style="width: 310px"><a
href="http://blog.oncode.info/wp-content/uploads/2011/03/codebrowser.png"><img
src="http://blog.oncode.info/wp-content/uploads/2011/03/codebrowser-300x166.png" alt="" title="codebrowser" width="300" height="166" class="size-medium wp-image-1798" /></a><p
class="wp-caption-text">Codebrowser Output</p></div><br
/> Ein Coverage-Report der Unittests unter <tt>statistics/html/unittests/coverage/</tt>:<br
/><div
id="attachment_1799" class="wp-caption alignnone" style="width: 310px"><a
href="http://blog.oncode.info/wp-content/uploads/2011/03/coverage.png"><img
src="http://blog.oncode.info/wp-content/uploads/2011/03/coverage-300x127.png" alt="" title="coverage" width="300" height="127" class="size-medium wp-image-1799" /></a><p
class="wp-caption-text">Coverage Report</p></div><br
/> Zwei nette Diagramme von PHP-Depend (eine <a
href="http://pdepend.org/documentation/handbook/reports/abstraction-instability-chart.html">Abstraction Instability Chart</a> und eine <a
href="http://pdepend.org/documentation/handbook/reports/overview-pyramid.html">Overview Pyramid</a>) unter <tt>statistics/html/jdepend</tt>:<br
/> <embed
height="300" src="http://blog.oncode.info/wp-content/uploads/2011/03/pyramid-overview.svg"" type="image/svg+xml" width="500"></embed><br
/> <embed
height="300" src="http://blog.oncode.info/wp-content/uploads/2011/03/dependencies.svg" type="image/svg+xml" width="500"></embed></p><h3>Fazit</h3><p>In einem n&#228;chsten Beitrag werde ich noch weitere Tools vorstellen und dann soll das alles ganz automatisch bei jeder &#196;nderung geschehen&#8230; Stay tuned&#8230;</p> <div class="feedflare">
<a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=cEjiHwea82I:SNmdMmHD79c:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=cEjiHwea82I:SNmdMmHD79c:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=cEjiHwea82I:SNmdMmHD79c:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=cEjiHwea82I:SNmdMmHD79c:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=cEjiHwea82I:SNmdMmHD79c:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=cEjiHwea82I:SNmdMmHD79c:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechnikGothicUndAnderes/~4/cEjiHwea82I" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.oncode.info/2011/03/02/php-code-analyse-mit-ant/feed/</wfw:commentRss> <slash:comments>3</slash:comments> <series:name><![CDATA[Continuous Integration]]></series:name> <feedburner:origLink>http://blog.oncode.info/2011/03/02/php-code-analyse-mit-ant/</feedburner:origLink></item> <item><title>Ich weiss (nicht mehr) ob Du im Facebook bist…</title><link>http://feeds.oncode.info/~r/TechnikGothicUndAnderes/~3/z4iPkGMUj8g/</link> <comments>http://blog.oncode.info/2011/01/24/ich-weiss-ob-du-im-facebook-bist/#comments</comments> <pubDate>Mon, 24 Jan 2011 12:38:43 +0000</pubDate> <dc:creator>skaldrom</dc:creator> <category><![CDATA[Webapplikationen]]></category> <category><![CDATA[ajax]]></category> <category><![CDATA[Datenschutz]]></category> <category><![CDATA[Facebook]]></category> <category><![CDATA[Hacking]]></category> <category><![CDATA[Moodle]]></category> <category><![CDATA[PHP]]></category> <guid isPermaLink="false">http://blog.oncode.info/?p=1700</guid> <description><![CDATA[Ein kleiner Trick erm&#246;glicht es, herauszufinden ob der aktuelle Website-User in Facebook und Co eingeloggt ist.]]></description> <content:encoded><![CDATA[<p><strong>Update 27.01.2011:</strong> *&#252;bel_fluch*! Facebook hat ein Captcha eingebaut, dass diese Detection momentan nicht mehr funktionieren l&#228;sst. Das Prinzip bleibt ok, die Realisierung brauchte nun etwas mehr Zeit.</p><p><img
src="http://blog.oncode.info/wp-content/uploads/2011/01/bigbrother.png" alt="Big Brother" title="bigbrother" width="266" height="207" class="lead" align="left" />Eigentlich h&#228;tte ich ja ganz Anderes zu tun, aber per Zufall bin ich &#252;ber den <a
href="https://grepular.com/Abusing_HTTP_Status_Codes_to_Expose_Private_Information">genialen Blogartikel von Mike Cardwell</a> gestolpert. Er hat eine Idee gehabt, wie es m&#246;glich wird herauszufinden, ob Benutzer auf Facebook und Konsorten eingeloggt sind oder nicht.</p><p>Umgesetzt in eine kleine Library l&#228;uft es als Proof-of-Concept <em>auf Firefox</em> und sieht folgendermassen aus:<script src="/wp-content/uploads/2011/01/distractor.php?callback=/wp-content/uploads/2011/01/result.php" type="text/javascript"></script></p><div
id="distractor-results"></div><div
id="distractor-noresults">Loggen Sie in Gmail, Facebook, Twitter oder Digg ein um Resultate zu sehen.</div><div
id="distractor-hasresults">Sind Sie nicht abgelenkt?</div><p><a
href="javascript:doChecks()">Neuer Check</a></p><p>Grunds&#228;tzlich w&#228;re es ja ganz einfach: Man schaut vom Client-Browser aus, ob man Zugriff auf Bilder oder Seiten hat, die nur f&#252;r Eingeloggte zur Verf&#252;gung stehen. Leider gestaltet sich dieser simple Ansatz nicht so einfach, weil mit Ajax nur zur Domain der Website verbunden werden darf und nicht an einen x-beliebigen Ort. Ein Proxy hilft auch nicht weiter, da es die Cookies des Browsers braucht, und die werden nur an Facebook, etc direkt abgeliefert.</p><p>Wie kann man also diese Restriktion umgehen?</p><h3>Der Trick</h3><p>Die geniale Idee von Mike Cardwell war nun, <a
href="http://de.wikipedia.org/wiki/Cross-Site_Request_Forgery">CSRF</a> etwas zu tunen: <tt>&lt;img&gt;</tt> und <tt>&lt;script&gt;</tt> Tags im Browser d&#252;rfen Dinge von &#252;berallher laden. Normalerweise ist das Handlungspotential damit sehr eingeschr&#228;nkt, ausser man nutzt die <tt>onerror</tt> und <tt>onload</tt> Attribute clever aus. Mit diesen Attrbuten k&#246;nnen abh&#228;ngig davon, ob ein Bild oder ein Script erfolgreich eingebunden werden konnte, JavaScript-Funktionen ausgef&#252;hrt werden. <tt>onerror</tt> feuert normalerweise bei den HTTP-Status Codes 404, 403, 406 oder 500.</p><p>Was tun wir also? Wir binden auf unserer &#8220;b&#246;sen&#8221; Seite ein Bild ein oder laden ein Script (kann auch eine Website sein), das sich unterschiedlich verh&#228;lt, je nachdem ob man eingeloggt ist oder nicht. In einem der F&#228;lle muss ein Fehler auftreten, damit dieser Trick klappt. &#220;ber das aufgerufene JavaScript senden wir das Resultat an den Server und schwuppdiwupps sind wir informiert.</p><p>Praktisch sieht das in etwa so aus: Mein Facebook-Profil ist nur f&#252;r eingeloggte sichtbar, ansonsten gibt es ein 404.<br
/> [cc lang="javascript"]<br
/> <script type="text/javascript"
  src="https://www.facebook.com/Skaldrom.Y.Sarg"
  onload="alert('Eingeloggt')"
  onerror="alert('Nicht eingeloggt')"
></script><br
/> [/cc]</p><p>Genau gleich l&#228;uft es mit Bildern.</p><h3>Proof of Concept</h3><p>Ich habe das Ganze etwas dynamisiert und in eine PHP-Bibliothek gefasst (die auch in diesem Beitrag f&#252;r das obige Beispiel verwendet wird). Daf&#252;r gibt es eine <a
href="http://apps.oncode.info/oncode/distractor/example.php">Demo mit Minimalanleitung</a>. Als grundlos b&#246;sartiger Mensch habe ich das in einen <a
href="http://moodle.org">Moodle</a>-Block gepackt. Die Kursteilnehmer werden dabei h&#246;flich gefragt, ob sie durch das Facebook vielleicht abgelenkt sind:<br
/> <img
src="http://blog.oncode.info/wp-content/uploads/2011/01/de-full.png" alt="Moodle Ablenkungsblock" title="Moodle Ablenkungsblock" width="192" height="173" class="alignnone size-full wp-image-1719" /><br
/> Heruntergeladen werden kann der Block von <a
href="http://www.oncode.info/de/project/de-distractorblock">oncode.info</a>.</p><h3>Hilfe</h3><p>Im Moment erkennt die Library Facebook, Google (gmail), Digg und Twitter. Sehr interessant w&#228;ren YouTube, Reddit, &#8230; Wenn also jemand hier Bilder oder Seiten findet, die abh&#228;ngig davon, ob man eingeloggt ist oder nicht, einen Fehler-Statuscode zur&#252;ckgeben oder nicht, w&#228;re ich sehr dankbar f&#252;r eine Mitteilung.</p><p>Die img-Attacke scheint auf allen Browsern zu funktionieren, die script-Attacke leider nicht. Wenn jemand kompetentes es auf sich nehmen m&#246;chte und MSIE oder Opera auch integriert, f&#228;nde ich das genial&#8230;</p><p>Happy Hacking <img
src='http://blog.oncode.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> &#8230;.</p> <div class="feedflare">
<a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=z4iPkGMUj8g:1hDinxh6s2Y:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=z4iPkGMUj8g:1hDinxh6s2Y:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=z4iPkGMUj8g:1hDinxh6s2Y:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=z4iPkGMUj8g:1hDinxh6s2Y:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=z4iPkGMUj8g:1hDinxh6s2Y:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=z4iPkGMUj8g:1hDinxh6s2Y:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechnikGothicUndAnderes/~4/z4iPkGMUj8g" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.oncode.info/2011/01/24/ich-weiss-ob-du-im-facebook-bist/feed/</wfw:commentRss> <slash:comments>9</slash:comments> <feedburner:origLink>http://blog.oncode.info/2011/01/24/ich-weiss-ob-du-im-facebook-bist/</feedburner:origLink></item> <item><title>Der UPnP Medienserver mit dem “Wow”</title><link>http://feeds.oncode.info/~r/TechnikGothicUndAnderes/~3/VwMPcpM_ySw/</link> <comments>http://blog.oncode.info/2010/12/24/der-upnp-medienserver-mit-dem-wow/#comments</comments> <pubDate>Fri, 24 Dec 2010 19:32:36 +0000</pubDate> <dc:creator>skaldrom</dc:creator> <category><![CDATA[Hardware]]></category> <category><![CDATA[Linux]]></category> <category><![CDATA[Bravia]]></category> <category><![CDATA[DLNA]]></category> <category><![CDATA[Medienserver]]></category> <category><![CDATA[mkv]]></category> <category><![CDATA[playstation]]></category> <category><![CDATA[ps3]]></category> <category><![CDATA[Sony]]></category> <category><![CDATA[upnp]]></category> <guid isPermaLink="false">http://blog.oncode.info/?p=1676</guid> <description><![CDATA[Der ps3-Mediaserver bringts: Nicht nur f&#252;r die Playstation 3, sondern auch f&#252;r den Sony Bravia EX5, etc...]]></description> <content:encoded><![CDATA[<p><img
src="http://blog.oncode.info/wp-content/uploads/2010/12/stream.png" alt="" title="stream" width="172" height="136" class="lead" align="left"/>W&#228;hrend Andere von ihren Liebsten eine Kravatte geschenkt bekommen, habe ich heute eine Playstation 3 vom Kristkind erhalten *freu*. Ein unglaubliches Teil, das mich schon voll in den Bann gezogen hat. Das Gamen damit ist psychisch: Man schwankt zwischen &#8220;Wow, ist das realistisch&#8221;, einem epileptischen Anfall und einem Amoklauf. Auf jeden Fall habe ich alle meine Pendenzen ein paar Tage nach hinten verschoben.</p><p>Die PS3 kann auch als UPnP-Client dienen und Filmchen, etc streamen. &#220;ber das Problem <a
href="/2010/11/18/handlicher-upnp-medienserver-fuer-linux/">habe ich schon mal geschrieben</a>. Auch hier ist man eingeschr&#228;nkt mit den Formaten und das Pladden hin- und hertragen geht auf den Senkel. Ausserdem sind die HD-Filmchen auf Grund ihrer Gr&#246;sse nicht mehr auf die Festplatte zu kriegen und das MKV-Format ist gar konvertierunfreundlich.</p><p>Per Zufall bin ich nun auf einen Medienserver gestossen, der on-the-fly konvertiert und die Filmchen nicht nur auf die PS3 streamt, sondern auch den Sony Bravia bedienen kann: Der <a
href="http://code.google.com/p/ps3mediaserver/">PS3 Mediaserver</a>. Kein Gekonfiguriere, kein Decodergewurschtel, kein Bittebitte: Starten und er l&#228;uft. Auf dem Bild sieht man sogar, dass er alle meine anderen Ger&#228;tchen auch auff&#252;hrt. Der &#8220;Unknown Renderer&#8221; ist &#252;brigens mein <a
href="/2010/11/25/archos-10-1-ein-geiles-geraet/">Archos 101</a>, der ebenfalls ganz willig die Filmchen abspielt, &#252;berall im Haus. Einfach genial!</p><p><a
href="http://blog.oncode.info/wp-content/uploads/2010/12/ps3mediaserver.png"><img
src="http://blog.oncode.info/wp-content/uploads/2010/12/ps3mediaserver-300x225.png" alt="" title="ps3mediaserver" width="300" height="225" class="alignnone size-medium wp-image-1677" /></a></p><p>So, ich muss jetzt was kuckn gehn und die Zeit, die ich durch das nicht-Transcoden gespart habe sinnvoll einsetzen <img
src='http://blog.oncode.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> &#8230;</p> <div class="feedflare">
<a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=VwMPcpM_ySw:SO0Bscl3UAw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=VwMPcpM_ySw:SO0Bscl3UAw:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=VwMPcpM_ySw:SO0Bscl3UAw:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=VwMPcpM_ySw:SO0Bscl3UAw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=VwMPcpM_ySw:SO0Bscl3UAw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=VwMPcpM_ySw:SO0Bscl3UAw:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechnikGothicUndAnderes/~4/VwMPcpM_ySw" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.oncode.info/2010/12/24/der-upnp-medienserver-mit-dem-wow/feed/</wfw:commentRss> <slash:comments>6</slash:comments> <feedburner:origLink>http://blog.oncode.info/2010/12/24/der-upnp-medienserver-mit-dem-wow/</feedburner:origLink></item> <item><title>Swisscom Labs mit (beta) Apps und Technik-Infos</title><link>http://feeds.oncode.info/~r/TechnikGothicUndAnderes/~3/IOhEslb3hH0/</link> <comments>http://blog.oncode.info/2010/12/19/swisscom-labs-mit-beta-apps-und-technik-infos/#comments</comments> <pubDate>Sun, 19 Dec 2010 12:59:31 +0000</pubDate> <dc:creator>skaldrom</dc:creator> <category><![CDATA[Web]]></category> <category><![CDATA[Beta]]></category> <category><![CDATA[co-creation]]></category> <category><![CDATA[Labs]]></category> <category><![CDATA[News]]></category> <category><![CDATA[Open Innovation]]></category> <category><![CDATA[Swisscom]]></category> <guid isPermaLink="false">http://blog.oncode.info/?p=1639</guid> <description><![CDATA[Die Swisscom Labs ist eine neue Website f&#252;r Technikaffine und Early Adopters; Also wie geschaffen f&#252;r uns GeekyTechs :)... ]]></description> <content:encoded><![CDATA[<p><a
href="http://labs.swisscom.ch/" rel="nofollow"><img
src="http://blog.oncode.info/wp-content/uploads/2010/12/swisscom.png" alt="swisscom logo" title="swisscom" width="187" height="180" class="lead" align="right" /></a>[<a
href="http://www.trigami.com/?blog=http://blog.oncode.info/" rel="nofollow" target="_blank">Trigami-Review</a>]<script type="text/javascript" src="http://s.trigami.com/390235s.js"></script><br
/> Wie klingt das: &#8220;Eine Schweizer Website f&#252;r Technikaffine mit News, der M&#246;glichkeit als &#8220;Early Adopter&#8221; Services, Apps und Neues zu testen, Erfahrungen auszutauschen sowie eine Plattform f&#252;r Entwickler.&#8221;? Passt doch wie die Faust aufs Auge! Und dahinter steht niemand geringerer als die Swisscom selbst: Sie hat die <a
href="http://labs.swisscom.ch/" rel="nofollow">Swisscom Labs</a> ins Leben gerufen. Beim Schm&#246;kern merkt man, dass die Site noch neu ist, aber mit sehr viel Enthusiasmus und Aufwand gef&#246;rdert wird. Mit Wettbewerben, Aktionen wie &#8220;<a
href="http://labs.swisscom.ch/en/content/ask-ceo" rel="nofollow">Ask the CEO</a>&#8221; und verschiedenen Events wird das Community-Building vorangetrieben. Das lasse ich mir als &#8220;Zielpublikum&#8221; nat&#252;rlich gerne gefallen.</p><h3>Was gibts auf den Swisscon Labs?</h3><h4>News</h4><p>Die News, die auf der Site pr&#228;sentiert werden, sind zum Einen aus der vordersten Front (Beispielsweise &#8220;<a
href="http://labs.swisscom.ch/en/content/ein-gebogener-multi-touch-arbeitstisch" rel="nofollow">Ein gebogener Multi-Touch-Arbeitstisch</a>&#8220;), geekig (&#8220;<a
href="http://labs.swisscom.ch/de/content/antikes-mit-%C2%ABlego-technic%C2%BB-nachgebaut" rel="nofollow">Antikes mit «Lego Technic» nachgebaut</a>&#8220;) oder aus dem Hause Swisscom selbst (wie &#8220;<a
href="http://labs.swisscom.ch/de/content/swisscom-und-ictnet-pr%C3%A4mieren-beste-diplomarbeit-im-ict-bereich" rel="nofollow">Swisscom und ICTnet pr&#228;mieren beste Diplomarbeit im ICT-Bereich</a>&#8220;). Alles in Allem eine gute und interessante Mischung von Themen, die in einem angenehmen Rhythmus publiziert werden.</p><h4>Apps</h4><p>DAS k&#246;nnte spannend werden: Ein interessantes Sammelsurium aus Android, I-Phone und Web-Applikationen. Hier finden sich Apps von Swisscom und auch von anderen Anbietern. Einige der Apps sind gebrauchsfertig, andere wiederum sind eher Betas. Laut <a
href="http://labs.swisscom.ch/de/faq" rel="nofollow">FAQ</a> k&#246;nnte man hier auch eigene Entwicklungen publizieren, wenn sie gewissen Anforderungen gen&#252;gen. Diese App-Abteilung hat das Potential, ein Platz f&#252;r lokale/nationale Applikationen zu werden, die in erster Linie die Schweiz betreffen. In den Markets findet man diese sonst leider eher schlecht, weil sie in der Masse untergehen. Ich glaube nicht, dass die Swisscom einen eigenen, ausgewachsenen App-Market hochziehen m&#246;chte, aber vielleicht erh&#228;lt sie auf diese Art und Weise befruchtende Ideen oder Apps, die das Netz ausnutzen&#8230;.</p><h4>Forum</h4><p>Ein Forum zum Laufen zu kriegen &#8211; vorallem wenn die Inhalte nicht sehr kontrovers sind &#8211; ist schwer. Die Swisscom hat hier richtig gehandelt und ein einzelnes Forum (ohne Unterthemen) aufgeschaltet. Ich sch&#228;tze den freundlichen und h&#246;flichen Umgangston der in diesem Forum herrscht sehr. Ein sehr angenehmer Gegensatz zu anderen Fach-Plattformen.</p><p>Technisch ist es etwas verwunderlich, dass die Links im Forum nicht mit &#8220;<a
href="http://de.wikipedia.org/wiki/Nofollow" rel="nofollow">nofollow</a>&#8221; gekennzeichnet werden. Einige Spammer haben bereits Witterung aufgenommen. Ich bin aber fest davon &#252;berzeugt, dass die Admins das bald im Griff haben werden.</p><h3>Community-Building</h3><p>Auf der Site gibt es ein <a
href="http://labs.swisscom.ch/de/content/achievements" rel="nofollow">Ranking-System</a> (fast wie bei <a
href="http://answers.yahoo.com/" rel="nofollow">Yahoo-Answers</a> oder <a
href="http://stackoverflow.com/" rel="nofollow">StackOverflow</a>). F&#252;r bestimmte Aktionen gibt es Punkte, und mit den Punkten steigt man in der Level-Hierarchie auf. Die Leute mit den h&#246;chsten Levels werden zum &#8220;Labs Event&#8221; eingeladen und besitzen auch ganz Allgemein eine h&#246;here &#8220;Credibility&#8221;.</p><p>Eine sehr interessante Idee ist der <a
href="http://labs.swisscom.ch/#hideContent" rel="nofollow">Community-Tree</a>, der laut <a
href="http://labs.swisscom.ch/en/faq" rel="nofollow">FAQ</a> von zwei ziemlich interessanten Firmen hergestellt wurde. Er stellt Benutzer, Posts und Aktivit&#228;ten dar. Je mehr Punkte ein Posting oder ein Benutzer hat, desto gr&#246;sser seine Repr&#228;sentation im Tree. Beim Klick auf einen Benutzer passiert gar wunderliches: Es entstehen Linien, die zeigen, mit welchen Posts und Benutzern der User vor Kurzem interagiert hat. Nun, es ist nett anzusehen, aber irgendwie beginnt hier mein Privacy-Warner zu blinken: Ich m&#246;chte nicht unbedingt, dass andere Benutzer sehen k&#246;nnen mit wem ich Kontakt pflege, beziehungsweise welche Infos ich mir ansehe.</p><p><object
width="480" height="385"><param
name="movie" value="http://www.youtube.com/v/VgbccqzpUjo?fs=1&amp;hl=en_US"></param><param
name="allowFullScreen" value="true"></param><param
name="allowscriptaccess" value="always"></param><embed
src="http://www.youtube.com/v/VgbccqzpUjo?fs=1&amp;hl=en_US" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"></embed></object></p><h3>Fazit</h3><p>Die Site ist klar und sauber aufgebaut, es steckt viel Enthusiasmus dahinter und die anderen Benutzer sind interessiert und freundlich. Man merkt sehr deutlich, dass sie sich noch im Aufbau befindet. Dies ist aber ganz klar als positiv anzusehen, da die Macher sehr interessiert an Meinungen und Feedback sind und somit der Weg der Site mitgestaltet werden kann. Es w&#252;rde mich freuen, wenn noch mehr Geeks, Nerds, Freaks und normale Menschen der Site eine Chance geben w&#252;rden und man sich dort treffen k&#246;nnte.</p> <div class="feedflare">
<a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=IOhEslb3hH0:bC2QFwfub1Q:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=IOhEslb3hH0:bC2QFwfub1Q:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=IOhEslb3hH0:bC2QFwfub1Q:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=IOhEslb3hH0:bC2QFwfub1Q:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=IOhEslb3hH0:bC2QFwfub1Q:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=IOhEslb3hH0:bC2QFwfub1Q:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechnikGothicUndAnderes/~4/IOhEslb3hH0" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.oncode.info/2010/12/19/swisscom-labs-mit-beta-apps-und-technik-infos/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://blog.oncode.info/2010/12/19/swisscom-labs-mit-beta-apps-und-technik-infos/</feedburner:origLink></item> <item><title>Mehr Glück als Verstand: Der Linux-Magazin Wettbewerb ist ausgefochten</title><link>http://feeds.oncode.info/~r/TechnikGothicUndAnderes/~3/vUwgUp7mk_s/</link> <comments>http://blog.oncode.info/2010/12/14/mehr-glueck-als-verstand-der-linux-magazin-wettbewerb-ist-ausgefochten/#comments</comments> <pubDate>Tue, 14 Dec 2010 10:48:05 +0000</pubDate> <dc:creator>skaldrom</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[Pig Dice]]></category> <category><![CDATA[Programmieren]]></category> <category><![CDATA[Programmierspiele]]></category> <category><![CDATA[Wettbewerb]]></category> <guid isPermaLink="false">http://blog.oncode.info/?p=1627</guid> <description><![CDATA[Der Linuxmagazin-Programmierwettbewerb ist durch. Mit einer abgewandelten, optimalen Pig-Dice Taktik habe ich es auf Platz 16 geschafft *freu*.]]></description> <br /> <b>Warning</b>:  Cannot use a scalar value as an array in <b>/home/oncodein/public_html/blogoncodeinfo/wp-content/plugins/organize-series/orgSeries-template-tags.php</b> on line <b>46</b><br /> <br /> <b>Warning</b>:  Invalid argument supplied for foreach() in <b>/home/oncodein/public_html/blogoncodeinfo/wp-content/plugins/organize-series/orgSeries-template-tags.php</b> on line <b>55</b><br /> <content:encoded><![CDATA[<div
class="seriesmeta">Dieser Beitrag ist Teil 3 von 3 in der Serie <a
href="http://blog.oncode.info/series/linux-magazin-wettbewerb/" class="series-977" title="Linux-Magazin Wettbewerb">Linux-Magazin Wettbewerb</a><ul
class="serieslist-ul"></ul></div><p>Viele haben nicht mehr daran geglaubt, aber der <a
href="http://wettbewerb.linux-magazin.de">Wettbewerb des Linuxmagazins</a> ist durchgef&#252;hrt worden: Im neusten Heft (01/11) sind die Gewinner abgedruckt. Siehe da, ich habs als einziger PHP-Frickler in die Top-20 geschafft:</p><p><img
src="http://blog.oncode.info/wp-content/uploads/2010/12/rangliste.png" alt="" title="rangliste" width="330" height="312" class="alignnone size-full wp-image-1628" /></p><p>Das gute an Programmierwettbewerben ist, dass man mit einer solchen Rangierung f&#252;r die Zukunft ausgesorgt hat: Reichtum, Jugend, Sch&#246;nheit, Wein, willige Weiber und einen offiziellen Schutz vor Alterskurzsichtigkeit sind das Minimum das es zu gewinnen gab. &#196;hhm, nein, sorry, ich hab da was verwechselt.</p><p>Auf jeden Fall: Heeeeeeeeeeerzliche Gratulation den Gewinnern! Gut gemacht! Die Turnierergebnisse und Bots sollen laut Heft alsbald <a
href="ftp://ftp.linux-magazin.de/pub/listings/magazin/2011/01/wettbewerb/">downgeloaded</a> werden k&#246;nnen. Ganz im Sinne der Durchf&#252;hrung ist aber bis Dato noch nichts sichtbar. Ich werde sicher analysieren, warum der <a
href="http://www.frigidor.ch/">Frigidor</a> nicht weheheit vor mir liegt. Unter uns gesagt, ist er n&#228;mlich viel der bessere Programmierer (der liebe Gott hat mir daf&#252;r eine grosse Klappe geschenkt).</p><h3>Mein Wettbewerbseintrag</h3><h4>Vorgehen</h4><p>Zu Beginn habe viel experimentiert. Mit einem selbst geschriebenen Simulator habe ich mit einfacher Parametrisierung und naiver Taktik versucht, die Anzahl Transaktionen pro Spiel zu minimieren. Sp&#228;ter habe ich verschiedene Generationen meiner Bots auf dem offiziellen Trainingsserver in den Kampf geschickt. Von sehr umfangreichen, komplexen Taktiken habe ich wieder auf sehr einfache gewechselt, nur um dann wieder zur&#252;ck ins Komplexe zu wechseln. Ganz Grunds&#228;tzlich habe ich versucht, die Theorie mit der Praxis (Messungen und Statistiken) und dem Bauchgef&#252;hl zu verbinden.</p><h4>Die Implementation</h4><p>Leider bin ich kurz vor Schluss auf die Webseite gestossen, die das Problem sowohl <a
href="http://cs.gettysburg.edu/projects/pig/piglinks.html">akademisch</a> als auch <a
href="http://cs.gettysburg.edu/~tneller/nsf/pig/">praktisch</a> f&#252;r das Spiel &#8220;Pig Dice&#8221; gel&#246;st hat. Diese L&#246;sung habe ich auf die Regeln des Wettbewerbs angepasst, in Java vorberechnet und in meinem Wettbewerbsbot implementiert.</p><p>Der <a
href="http://blog.oncode.info/wp-content/uploads/2010/12/edocno.zip">Spieler</a> verwendet die vor-berechneten Spielz&#252;ge dieses Java-Programms:<br
/> [cc lang="java"]<br
/> public class PigSolver {</p><p> int goal;<br
/> double epsilon;<br
/> double[][][] p;<br
/> boolean[][][] roll;</p><p> PigSolver(int goal, double epsilon) {<br
/> this.goal = goal;<br
/> this.epsilon = epsilon;<br
/> p = new double[goal][goal][goal];<br
/> roll = new boolean[goal][goal][goal];</p><p> valueIterate();<br
/> }</p><p> void valueIterate() {<br
/> double maxChange;<br
/> do {<br
/> maxChange = 0.0;<br
/> for (int i = 0; i < goal; i++) // for all i<br
/> {<br
/> for (int j = 0; j < goal; j++) // for all j<br
/> {<br
/> for (int k = 0; k < goal - i; k++) { // for all k<br
/> double oldProb = p[i][j][k];<br
/> double pRoll = ((1.0 &#8211; pWin(j, i, 0)) + pWin(i, j, k + 1) + pWin(i, j, k + 2) + pWin(i, j, k + 3) + pWin(i, j, k + 4) + pWin(i, j, k + 5)) / 6;<br
/> double pHold = 1.0 &#8211; pWin(j, i + k, 0);<br
/> p[i][j][k] = Math.max(pRoll, pHold);<br
/> roll[i][j][k] = pRoll > pHold;<br
/> double change = Math.abs(p[i][j][k] &#8211; oldProb);<br
/> maxChange = Math.max(maxChange, change);<br
/> }<br
/> }<br
/> }<br
/> } while (maxChange >= epsilon);<br
/> }</p><p> public double pWin(int i, int j, int k) {<br
/> if (i + k >= goal) {<br
/> return 1.0;<br
/> } else if (j >= goal) {<br
/> return 0.0;<br
/> } else {<br
/> return p[i][j][k];<br
/> }<br
/> }</p><p> public void outputHoldValues() {<br
/> for (int i = 0; i < goal; i++) {<br
/> for (int j = 0; j < goal; j++) {<br
/> int k = 0;<br
/> while (k < goal - i &#038;&#038; roll[i][j][k]) {<br
/> k++;<br
/> }<br
/> System.out.print(k + &#8221; &#8220;);<br
/> }<br
/> System.out.println();<br
/> }<br
/> }</p><p> public void summarize() {<br
/> System.out.println(&#8220;p[0][0][0] = &#8221; + p[0][0][0]);<br
/> System.out.println();<br
/> System.out.println(&#8220;i\tj\tPolicy changes at k =&#8221;);<br
/> for (int i = 0; i < goal; i++) // for all i<br
/> {<br
/> for (int j = 0; j < goal; j++) { // for all j<br
/> int k = 0;<br
/> System.out.print(i + &#8220;\t&#8221; + j + &#8220;\t&#8221; + (roll[i][j][k] ? &#8220;roll &#8221; : &#8220;save &#8220;));<br
/> for (k = 1; i + k < goal; k++) // for all valid k<br
/> {<br
/> if (roll[i][j][k] != roll[i][j][k - 1]) {<br
/> System.out.print(k + &#8221; &#8221; + (roll[i][j][k] ? &#8220;roll &#8221; : &#8220;save &#8220;));<br
/> }<br
/> }<br
/> System.out.println();<br
/> }<br
/> }<br
/> }</p><p> public void summarizePHP() {<br
/> System.out.println(&#8220;$optimalWin = array();&#8221;);<br
/> for (int i = 0; i < goal; i++) // for all i<br
/> {<br
/> for (int j = 0; j < goal; j++) { // for all j<br
/> int k = 0;<br
/> System.out.println(&#8220;$optimalWin["+i+"][" + j + "][0]=&#8217;&#8221; + (roll[i][j][k] ? &#8220;roll&#8221; : &#8220;save&#8221;) + &#8220;&#8216;;&#8221;);<br
/> for (k = 1; i + k < goal; k++) // for all valid k<br
/> {<br
/> if (roll[i][j][k] != roll[i][j][k - 1]) {<br
/> System.out.println(&#8221;  $optimalWin["+i+"][" + j + "]["+k+"]=&#8217;&#8221; + (roll[i][j][k] ? &#8220;roll&#8221; : &#8220;save&#8221;) + &#8220;&#8216;;&#8221;);<br
/> }<br
/> }<br
/> }<br
/> }<br
/> }</p><p> public static void main(String[] args) {<br
/> //new PigSolver(100, 1e-9).outputHoldValues();<br
/> //new PigSolver(50, 1e-10).summarizePHP();<br
/> new PigSolver(50, 1e-15).summarize();<br
/> }<br
/> }<br
/> [/cc]</p> <div class="feedflare">
<a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=vUwgUp7mk_s:HDJXF0uEaXQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=vUwgUp7mk_s:HDJXF0uEaXQ:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=vUwgUp7mk_s:HDJXF0uEaXQ:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=vUwgUp7mk_s:HDJXF0uEaXQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?i=vUwgUp7mk_s:HDJXF0uEaXQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.oncode.info/~ff/TechnikGothicUndAnderes?a=vUwgUp7mk_s:HDJXF0uEaXQ:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/TechnikGothicUndAnderes?d=7Q72WNTAKBA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TechnikGothicUndAnderes/~4/vUwgUp7mk_s" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.oncode.info/2010/12/14/mehr-glueck-als-verstand-der-linux-magazin-wettbewerb-ist-ausgefochten/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <series:name><![CDATA[Linux-Magazin Wettbewerb]]></series:name> <feedburner:origLink>http://blog.oncode.info/2010/12/14/mehr-glueck-als-verstand-der-linux-magazin-wettbewerb-ist-ausgefochten/</feedburner:origLink></item> </channel> </rss><!-- Dynamic page generated in 1.327 seconds. --><!-- Cached page generated by WP-Super-Cache on 2013-04-26 03:20:27 --><!-- Compression = gzip -->
