Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  Source.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "debugger/Source.h"

#include "mozilla/Assertions.h"  // for AssertionConditionType, MOZ_ASSERT
#include "mozilla/Maybe.h"       // for Some, Maybe, Nothing
#include "mozilla/Variant.h"     // for AsVariant, Variant

#include <stdint.h>  // for uint32_t
#include <string.h>  // for memcpy
#include <utility>   // for move

#include "debugger/Debugger.h"         // for DebuggerSourceReferent, Debugger
#include "debugger/Script.h"           // for DebuggerScript
#include "frontend/FrontendContext.h"  // for AutoReportFrontendContext
#include "gc/Tracer.h"        // for TraceManuallyBarrieredCrossCompartmentEdge
#include "js/ColumnNumber.h"  // JS::WasmFunctionIndex, JS::ColumnNumberOneOrigin
#include "js/CompilationAndEvaluation.h"  // for Compile
#include "js/ErrorReport.h"  // for JS_ReportErrorASCII,  JS_ReportErrorNumberASCII
#include "js/experimental/TypedData.h"  // for JS_NewUint8Array
#include "js/friend/ErrorMessages.h"    // for GetErrorMessage, JSMSG_*
#include "js/GCVariant.h"               // for GCVariant
#include "js/SourceText.h"              // for JS::SourceOwnership
#include "js/String.h"                  // for JS_CopyStringCharsZ
#include "vm/BytecodeUtil.h"            // for JSDVG_SEARCH_STACK
#include "vm/JSContext.h"               // for JSContext (ptr only)
#include "vm/JSObject.h"                // for JSObject, RequireObject
#include "vm/JSScript.h"                // for ScriptSource, ScriptSourceObject
#include "vm/StringType.h"        // for NewStringCopyZ, JSString (ptr only)
#include "vm/TypedArrayObject.h"  // for TypedArrayObject, JSObject::is
#include "wasm/WasmCode.h"        // for Metadata
#include "wasm/WasmDebug.h"       // for DebugState
#include "wasm/WasmInstance.h"    // for Instance
#include "wasm/WasmJS.h"          // for WasmInstanceObject
#include "wasm/WasmTypeDecls.h"   // for Bytes, Rooted<WasmInstanceObject*>

#include "debugger/Debugger-inl.h"  // for Debugger::fromJSObject
#include "vm/JSObject-inl.h"        // for InitClass
#include "vm/NativeObject-inl.h"    // for NewTenuredObjectWithGivenProto
#include "wasm/WasmInstance-inl.h"

namespace js {
class GlobalObject;
}

using namespace js;

using mozilla::AsVariant;
using mozilla::Maybe;
using mozilla::Nothing;
using mozilla::Some;

const JSClassOps DebuggerSource::classOps_ = {
    nullptr,                          // addProperty
    nullptr,                          // delProperty
    nullptr,                          // enumerate
    nullptr,                          // newEnumerate
    nullptr,                          // resolve
    nullptr,                          // mayResolve
    nullptr,                          // finalize
    nullptr,                          // call
    nullptr,                          // construct
    CallTraceMethod<DebuggerSource>,  // trace
};

const JSClass DebuggerSource::class_ = {
    "Source",
    JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS),
    &classOps_,
};

/* static */
NativeObject* DebuggerSource::initClass(JSContext* cx,
                                        Handle<GlobalObject*> global,
                                        HandleObject debugCtor) {
  return InitClass(cx, debugCtor, nullptr, nullptr, "Source", construct, 0,
                   properties_, methods_, nullptr, nullptr);
}

/* static */
DebuggerSource* DebuggerSource::create(JSContext* cx, HandleObject proto,
                                       Handle<DebuggerSourceReferent> referent,
                                       Handle<NativeObject*> debugger) {
  Rooted<DebuggerSource*> sourceObj(
      cx, NewTenuredObjectWithGivenProto<DebuggerSource>(cx, proto));
  if (!sourceObj) {
    return nullptr;
  }
  sourceObj->setReservedSlot(OWNER_SLOT, ObjectValue(*debugger));
  referent.get().match([&](auto sourceHandle) {
    sourceObj->setReservedSlotGCThingAsPrivate(SOURCE_SLOT, sourceHandle);
  });

  return sourceObj;
}

Debugger* DebuggerSource::owner() const {
  JSObject* dbgobj = &getReservedSlot(OWNER_SLOT).toObject();
  return Debugger::fromJSObject(dbgobj);
}

// For internal use only.
NativeObject* DebuggerSource::getReferentRawObject() const {
  return maybePtrFromReservedSlot<NativeObject>(SOURCE_SLOT);
}

DebuggerSourceReferent DebuggerSource::getReferent() const {
  if (NativeObject* referent = getReferentRawObject()) {
    if (referent->is<ScriptSourceObject>()) {
      return AsVariant(&referent->as<ScriptSourceObject>());
    }
    return AsVariant(&referent->as<WasmInstanceObject>());
  }
  return AsVariant(static_cast<ScriptSourceObject*>(nullptr));
}

void DebuggerSource::trace(JSTracer* trc) {
  // There is a barrier on private pointers, so the Unbarriered marking
  // is okay.
  if (JSObject* referent = getReferentRawObject()) {
    TraceManuallyBarrieredCrossCompartmentEdge(trc, this, &referent,
                                               "Debugger.Source referent");
    if (referent != getReferentRawObject()) {
      setReservedSlotGCThingAsPrivateUnbarriered(SOURCE_SLOT, referent);
    }
  }
}

/* static */
bool DebuggerSource::construct(JSContext* cx, unsigned argc, Value* vp) {
  JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
                            "Debugger.Source");
  return false;
}

/* static */
DebuggerSource* DebuggerSource::check(JSContext* cx, HandleValue thisv) {
  JSObject* thisobj = RequireObject(cx, thisv);
  if (!thisobj) {
    return nullptr;
  }
  if (!thisobj->is<DebuggerSource>()) {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_INCOMPATIBLE_PROTO, "Debugger.Source",
                              "method", thisobj->getClass()->name);
    return nullptr;
  }

  return &thisobj->as<DebuggerSource>();
}

struct MOZ_STACK_CLASS DebuggerSource::CallData {
  JSContext* cx;
  const CallArgs& args;

  Handle<DebuggerSource*> obj;
  Rooted<DebuggerSourceReferent> referent;

  CallData(JSContext* cx, const CallArgs& args, Handle<DebuggerSource*> obj)
      : cx(cx), args(args), obj(obj), referent(cx, obj->getReferent()) {}

  bool getText();
  bool getBinary();
  bool getURL();
  bool getStartLine();
  bool getStartColumn();
  bool getId();
  bool getDisplayURL();
  bool getElementProperty();
  bool getIntroductionScript();
  bool getIntroductionOffset();
  bool getIntroductionType();
  bool setSourceMapURL();
  bool getSourceMapURL();
  bool reparse();

  using Method = bool (CallData::*)();

  template <Method MyMethod>
  static bool ToNative(JSContext* cx, unsigned argc, Value* vp);
};

template <DebuggerSource::CallData::Method MyMethod>
/* static */
bool DebuggerSource::CallData::ToNative(JSContext* cx, unsigned argc,
                                        Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);

  Rooted<DebuggerSource*> obj(cx, DebuggerSource::check(cx, args.thisv()));
  if (!obj) {
    return false;
  }

  CallData data(cx, args, obj);
  return (data.*MyMethod)();
}

class DebuggerSourceGetTextMatcher {
  JSContext* cx_;

 public:
  explicit DebuggerSourceGetTextMatcher(JSContext* cx) : cx_(cx) {}

  using ReturnType = JSString*;

  ReturnType match(Handle<ScriptSourceObject*> sourceObject) {
    ScriptSource* ss = sourceObject->source();
    bool hasSourceText;
    if (!ScriptSource::loadSource(cx_, ss, &hasSourceText)) {
      return nullptr;
    }
    if (!hasSourceText) {
      return NewStringCopyZ<CanGC>(cx_, "[no source]");
    }

    // In case of DOM event handler like <div onclick="foo()" the JS code is
    // wrapped into
    //   function onclick() {foo()}
    // We want to only return `foo()` here.
    // But only for event handlers, for `new Function("foo()")`, we want to
    // return:
    //   function anonymous() {foo()}
    if (ss->hasIntroductionType() &&
        strcmp(ss->introductionType(), "eventHandler") == 0 &&
        ss->isFunctionBody()) {
      return ss->functionBodyString(cx_);
    }

    return ss->substring(cx_, 0, ss->length());
  }

  ReturnType match(Handle<WasmInstanceObject*> instanceObj) {
    wasm::Instance& instance = instanceObj->instance();
    const char* msg;
    if (!instance.debugEnabled()) {
      msg = "Restart with developer tools open to view WebAssembly source.";
    } else {
      msg = "[debugger missing wasm binary-to-text conversion]";
    }
    return NewStringCopyZ<CanGC>(cx_, msg);
  }
};

bool DebuggerSource::CallData::getText() {
  Value textv = obj->getReservedSlot(TEXT_SLOT);
  if (!textv.isUndefined()) {
    MOZ_ASSERT(textv.isString());
    args.rval().set(textv);
    return true;
  }

  DebuggerSourceGetTextMatcher matcher(cx);
  JSString* str = referent.match(matcher);
  if (!str) {
    return false;
  }

  args.rval().setString(str);
  obj->setReservedSlot(TEXT_SLOT, args.rval());
  return true;
}

bool DebuggerSource::CallData::getBinary() {
  if (!referent.is<WasmInstanceObject*>()) {
    ReportValueError(cx, JSMSG_DEBUG_BAD_REFERENT, JSDVG_SEARCH_STACK,
                     args.thisv(), nullptr, "a wasm source");
    return false;
  }

  Rooted<WasmInstanceObject*> instanceObj(cx,
                                          referent.as<WasmInstanceObject*>());
  wasm::Instance& instance = instanceObj->instance();

  if (!instance.debugEnabled()) {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_DEBUG_NO_BINARY_SOURCE);
    return false;
  }

  const wasm::Bytes& bytecode = instance.debug().bytecode();
  RootedObject arr(cx, JS_NewUint8Array(cx, bytecode.length()));
  if (!arr) {
    return false;
  }

  memcpy(arr->as<TypedArrayObject>().dataPointerUnshared(), bytecode.begin(),
         bytecode.length());

  args.rval().setObject(*arr);
  return true;
}

class DebuggerSourceGetURLMatcher {
  JSContext* cx_;

 public:
  explicit DebuggerSourceGetURLMatcher(JSContext* cx) : cx_(cx) {}

  using ReturnType = Maybe<JSString*>;

  ReturnType match(Handle<ScriptSourceObject*> sourceObject) {
    ScriptSource* ss = sourceObject->source();
    MOZ_ASSERT(ss);
    if (const char* filename = ss->filename()) {
      JS::UTF8Chars utf8chars(filename, strlen(filename));
      JSString* str = NewStringCopyUTF8N(cx_, utf8chars);
      return Some(str);
    }
    return Nothing();
  }
  ReturnType match(Handle<WasmInstanceObject*> instanceObj) {
    return Some(instanceObj->instance().createDisplayURL(cx_));
  }
};

bool DebuggerSource::CallData::getURL() {
  DebuggerSourceGetURLMatcher matcher(cx);
  Maybe<JSString*> str = referent.match(matcher);
  if (str.isSome()) {
    if (!*str) {
      return false;
    }
    args.rval().setString(*str);
  } else {
    args.rval().setNull();
  }
  return true;
}

class DebuggerSourceGetStartLineMatcher {
 public:
  using ReturnType = uint32_t;

  ReturnType match(Handle<ScriptSourceObject*> sourceObject) {
    ScriptSource* ss = sourceObject->source();
    return ss->startLine();
  }
  ReturnType match(Handle<WasmInstanceObject*> instanceObj) { return 0; }
};

bool DebuggerSource::CallData::getStartLine() {
  DebuggerSourceGetStartLineMatcher matcher;
  uint32_t line = referent.match(matcher);
  args.rval().setNumber(line);
  return true;
}

class DebuggerSourceGetStartColumnMatcher {
 public:
  using ReturnType = JS::LimitedColumnNumberOneOrigin;

  ReturnType match(Handle<ScriptSourceObject*> sourceObject) {
    ScriptSource* ss = sourceObject->source();
    return ss->startColumn();
  }
  ReturnType match(Handle<WasmInstanceObject*> instanceObj) {
    return JS::LimitedColumnNumberOneOrigin(
        JS::WasmFunctionIndex::DefaultBinarySourceColumnNumberOneOrigin);
  }
};

bool DebuggerSource::CallData::getStartColumn() {
  DebuggerSourceGetStartColumnMatcher matcher;
  JS::LimitedColumnNumberOneOrigin column = referent.match(matcher);
  args.rval().setNumber(column.oneOriginValue());
  return true;
}

class DebuggerSourceGetIdMatcher {
 public:
  using ReturnType = uint32_t;

  ReturnType match(Handle<ScriptSourceObject*> sourceObject) {
    ScriptSource* ss = sourceObject->source();
    return ss->id();
  }
  ReturnType match(Handle<WasmInstanceObject*> instanceObj) { return 0; }
};

bool DebuggerSource::CallData::getId() {
  DebuggerSourceGetIdMatcher matcher;
  uint32_t id = referent.match(matcher);
  args.rval().setNumber(id);
  return true;
}

struct DebuggerSourceGetDisplayURLMatcher {
  using ReturnType = const char16_t*;
  ReturnType match(Handle<ScriptSourceObject*> sourceObject) {
    ScriptSource* ss = sourceObject->source();
    MOZ_ASSERT(ss);
    return ss->hasDisplayURL() ? ss->displayURL() : nullptr;
  }
  ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
    return wasmInstance->instance().codeMetaForAsmJS()
               ? wasmInstance->instance()
                     .codeMetaForAsmJS()
                     ->displayURL()  // asm.js
               : nullptr;            // wasm
  }
};

bool DebuggerSource::CallData::getDisplayURL() {
  DebuggerSourceGetDisplayURLMatcher matcher;
  if (const char16_t* displayURL = referent.match(matcher)) {
    JSString* str = JS_NewUCStringCopyZ(cx, displayURL);
    if (!str) {
      return false;
    }
    args.rval().setString(str);
  } else {
    args.rval().setNull();
  }
  return true;
}

struct DebuggerSourceGetElementPropertyMatcher {
  using ReturnType = Value;
  ReturnType match(Handle<ScriptSourceObject*> sourceObject) {
    return sourceObject->unwrappedElementAttributeName();
  }
  ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
    return UndefinedValue();
  }
};

bool DebuggerSource::CallData::getElementProperty() {
  DebuggerSourceGetElementPropertyMatcher matcher;
  args.rval().set(referent.match(matcher));
  return obj->owner()->wrapDebuggeeValue(cx, args.rval());
}

class DebuggerSourceGetIntroductionScriptMatcher {
  JSContext* cx_;
  Debugger* dbg_;
  MutableHandleValue rval_;

 public:
  DebuggerSourceGetIntroductionScriptMatcher(JSContext* cx, Debugger* dbg,
                                             MutableHandleValue rval)
      : cx_(cx), dbg_(dbg), rval_(rval) {}

  using ReturnType = bool;

  ReturnType match(Handle<ScriptSourceObject*> sourceObject) {
    Rooted<BaseScript*> script(cx_,
                               sourceObject->unwrappedIntroductionScript());
    if (script) {
      RootedObject scriptDO(cx_, dbg_->wrapScript(cx_, script));
      if (!scriptDO) {
        return false;
      }
      rval_.setObject(*scriptDO);
    } else {
      rval_.setUndefined();
    }
    return true;
  }

  ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
    RootedObject ds(cx_, dbg_->wrapWasmScript(cx_, wasmInstance));
    if (!ds) {
      return false;
    }
    rval_.setObject(*ds);
    return true;
  }
};

bool DebuggerSource::CallData::getIntroductionScript() {
  Debugger* dbg = obj->owner();
  DebuggerSourceGetIntroductionScriptMatcher matcher(cx, dbg, args.rval());
  return referent.match(matcher);
}

struct DebuggerGetIntroductionOffsetMatcher {
  using ReturnType = Value;
  ReturnType match(Handle<ScriptSourceObject*> sourceObject) {
    // Regardless of what's recorded in the ScriptSourceObject and
    // ScriptSource, only hand out the introduction offset if we also have
    // the script within which it applies.
    ScriptSource* ss = sourceObject->source();
    if (ss->hasIntroductionOffset() &&
        sourceObject->unwrappedIntroductionScript()) {
      return Int32Value(ss->introductionOffset());
    }
    return UndefinedValue();
  }
  ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
    return UndefinedValue();
  }
};

bool DebuggerSource::CallData::getIntroductionOffset() {
  DebuggerGetIntroductionOffsetMatcher matcher;
  args.rval().set(referent.match(matcher));
  return true;
}

struct DebuggerSourceGetIntroductionTypeMatcher {
  using ReturnType = const char*;
  ReturnType match(Handle<ScriptSourceObject*> sourceObject) {
    ScriptSource* ss = sourceObject->source();
    MOZ_ASSERT(ss);
    return ss->hasIntroductionType() ? ss->introductionType() : nullptr;
  }
  ReturnType match(Handle<WasmInstanceObject*> wasmInstance) { return "wasm"; }
};

bool DebuggerSource::CallData::getIntroductionType() {
  DebuggerSourceGetIntroductionTypeMatcher matcher;
  if (const char* introductionType = referent.match(matcher)) {
    JSString* str = NewStringCopyZ<CanGC>(cx, introductionType);
    if (!str) {
      return false;
    }
    args.rval().setString(str);
  } else {
    args.rval().setUndefined();
  }

  return true;
}

ScriptSourceObject* EnsureSourceObject(JSContext* cx,
                                       Handle<DebuggerSource*> obj) {
  if (!obj->getReferent().is<ScriptSourceObject*>()) {
    RootedValue v(cx, ObjectValue(*obj));
    ReportValueError(cx, JSMSG_DEBUG_BAD_REFERENT, JSDVG_SEARCH_STACK, v,
                     nullptr, "a JS source");
    return nullptr;
  }
  return obj->getReferent().as<ScriptSourceObject*>();
}

bool DebuggerSource::CallData::setSourceMapURL() {
  Rooted<ScriptSourceObject*> sourceObject(cx, EnsureSourceObject(cx, obj));
  if (!sourceObject) {
    return false;
  }
  ScriptSource* ss = sourceObject->source();
  MOZ_ASSERT(ss);

  if (!args.requireAtLeast(cx, "set sourceMapURL", 1)) {
    return false;
  }

  JSString* str = ToString<CanGC>(cx, args[0]);
  if (!str) {
    return false;
  }

  UniqueTwoByteChars chars = JS_CopyStringCharsZ(cx, str);
  if (!chars) {
    return false;
  }

  AutoReportFrontendContext fc(cx);
  if (!ss->setSourceMapURL(&fc, std::move(chars))) {
    return false;
  }

  args.rval().setUndefined();
  return true;
}

class DebuggerSourceGetSourceMapURLMatcher {
  JSContext* cx_;
  MutableHandleString result_;

 public:
  explicit DebuggerSourceGetSourceMapURLMatcher(JSContext* cx,
                                                MutableHandleString result)
      : cx_(cx), result_(result) {}

  using ReturnType = bool;
  ReturnType match(Handle<ScriptSourceObject*> sourceObject) {
    ScriptSource* ss = sourceObject->source();
    MOZ_ASSERT(ss);
    if (!ss->hasSourceMapURL()) {
      result_.set(nullptr);
      return true;
    }
    JSString* str = JS_NewUCStringCopyZ(cx_, ss->sourceMapURL());
    if (!str) {
      return false;
    }
    result_.set(str);
    return true;
  }
  ReturnType match(Handle<WasmInstanceObject*> instanceObj) {
    wasm::Instance& instance = instanceObj->instance();
    if (!instance.debugEnabled()) {
      result_.set(nullptr);
      return true;
    }

    RootedString str(cx_);
    if (!instance.debug().getSourceMappingURL(cx_, &str)) {
      return false;
    }

    result_.set(str);
    return true;
  }
};

bool DebuggerSource::CallData::getSourceMapURL() {
  RootedString result(cx);
  DebuggerSourceGetSourceMapURLMatcher matcher(cx, &result);
  if (!referent.match(matcher)) {
    return false;
  }
  if (result) {
    args.rval().setString(result);
  } else {
    args.rval().setNull();
  }
  return true;
}

template <typename Unit>
static JSScript* ReparseSource(JSContext* cx, Handle<ScriptSourceObject*> sso) {
  AutoRealm ar(cx, sso);
  ScriptSource* ss = sso->source();

  JS::CompileOptions options(cx);
  options.setHideScriptFromDebugger(true);
  options.setFileAndLine(ss->filename(), ss->startLine());
  options.setColumn(JS::ColumnNumberOneOrigin(ss->startColumn()));

  UncompressedSourceCache::AutoHoldEntry holder;

  ScriptSource::PinnedUnits<Unit> units(cx, ss, holder, 0, ss->length());
  if (!units.get()) {
    return nullptr;
  }

  JS::SourceText<Unit> srcBuf;
  if (!srcBuf.init(cx, units.get(), ss->length(),
                   JS::SourceOwnership::Borrowed)) {
    return nullptr;
  }

  return JS::Compile(cx, options, srcBuf);
}

bool DebuggerSource::CallData::reparse() {
  Rooted<ScriptSourceObject*> sourceObject(cx, EnsureSourceObject(cx, obj));
  if (!sourceObject) {
    return false;
  }

  if (!sourceObject->source()->hasSourceText()) {
    JS_ReportErrorASCII(cx, "Source object missing text");
    return false;
  }

  RootedScript script(cx);
  if (sourceObject->source()->hasSourceType<mozilla::Utf8Unit>()) {
    script = ReparseSource<mozilla::Utf8Unit>(cx, sourceObject);
  } else {
    script = ReparseSource<char16_t>(cx, sourceObject);
  }

  if (!script) {
    return false;
  }

  Debugger* dbg = obj->owner();
  RootedObject scriptDO(cx, dbg->wrapScript(cx, script));
  if (!scriptDO) {
    return false;
  }

  args.rval().setObject(*scriptDO);
  return true;
}

const JSPropertySpec DebuggerSource::properties_[] = {
    JS_DEBUG_PSG("text", getText),
    JS_DEBUG_PSG("binary", getBinary),
    JS_DEBUG_PSG("url", getURL),
    JS_DEBUG_PSG("startLine", getStartLine),
    JS_DEBUG_PSG("startColumn", getStartColumn),
    JS_DEBUG_PSG("id", getId),
    JS_DEBUG_PSG("displayURL", getDisplayURL),
    JS_DEBUG_PSG("introductionScript", getIntroductionScript),
    JS_DEBUG_PSG("introductionOffset", getIntroductionOffset),
    JS_DEBUG_PSG("introductionType", getIntroductionType),
    JS_DEBUG_PSG("elementAttributeName", getElementProperty),
    JS_DEBUG_PSGS("sourceMapURL", getSourceMapURL, setSourceMapURL),
    JS_PS_END,
};

const JSFunctionSpec DebuggerSource::methods_[] = {
    JS_DEBUG_FN("reparse", reparse, 0),
    JS_FS_END,
};

Messung V0.5
C=93 H=92 G=92

¤ Dauer der Verarbeitung: 0.10 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge