Skip to main content

Jixun's Blog 填坑还是开坑,这是个好问题。

Mastodon

Patch Win32 Disk Imager to work with system has RamDisk

This problem was reported back in 2017: win32diskimager/tickets/47

A quick workaround was to assign drive A or B as the RamDisk, and don’t let Win32DiskImager to access it:

004066CC | C1EB 02     | shr ebx,2                  |
004066CF | 85DB        | test ebx,ebx               |
004066D1 | 74 27       | je win32diskimager.4066FA  |
004066D3 | 90          | nop                        |
004066D4 | BE 43000000 | mov esi,43                 | 43:'C'

Or, use the patcher below to specify the drive you would like to ignore:

Read more »

Simple implementation of createElement

Just a nice and simple alternative implementation of React.createElement.

var h = (function () {
  function deref(fn) {
    return Function.call.bind(fn);
  }

  var slice = deref(Array.prototype.slice);

  // Lodash code starts here
  var MAX_SAFE_INTEGER = 9007199254740991;

  function isObject(value) {
    var type = typeof value;
    return value != null && (type == 'object' || type == 'function');
  }

  function isLength(value) {
    return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
  }

  function isArrayLike(value) {
    return value != null && isLength(value.length) && !isFunction(value);
  }

  function isObjectLike(value) {
    return value != null && typeof value == 'object';
  }
  // Lodash code ends here

  function isFunction(value) {
    return value instanceof Function;
  }

  function makeArray(v) {
    return isArrayLike(v) && typeof v !== 'string' ? slice(v) : [v];
  }

  function isNode(el) {
    return el instanceof Node;
  }

  function isObjectLikeNotArray(value) {
    return isObjectLike(value) && !isArrayLike(value);
  }

  /**
   * 深度对象合并
   * @param {Object} src 需要扩展的对象。
   * @param {Object} [...ext] 待扩展的属性。
   */
  function merge(src) {
    slice(arguments, 1).forEach(function (ext) {
      if (isObjectLikeNotArray(ext)) {
        Object.keys(ext).forEach(function (key) {
          var value = ext[key];
          if (isObjectLikeNotArray(value)) {
            if (!src[key]) {
              src[key] = {};
            }
            merge(src[key], value);
          } else {
            src[key] = value;
          }
        });
      }
    });

    return src;
  }

  function appendChildren(container, children) {
    children.forEach(function (children) {
      makeArray(children).forEach(function (child) {
        if (child || child === '') {
          container.appendChild(isNode(child) ? child : document.createTextNode(child));
        }
      });
    });
    return container;
  }

  /**
   * 建立一个 HTML 元素
   * @param {String|Function} tag 元素标签,或传入 Stateless 组件函数。
   * @param {Object.<String.String|Bool|Number>} [attrs = {}] 元素属性集合。
   * @param {Array.<String|Node>|String|Node} [...children] 子元素集合。
   */
  function h(tag, attrs) {
    var children = slice(arguments, 2);

    // Stateless 组件建立
    if (isFunction(tag)) {
      return tag(Object.assign({ children }, attrs));
    }

    var el = merge(document.createElement(tag), attrs);
    return appendChildren(el, children);
  }

  h.Fragment = function Fragment({ children }) {
    return appendChildren(document.createDocumentFragment(), children);
  };

  return h;
})();

/**
 * 将建立的元素挂载到一个 HTML 节点 (会先暴力清空节点内容)。
 * @param {HTMLElement} mnt 挂载点。
 * @param {Node} node HTML 元素或节点。
 */
function mount(mnt, node) {
  mnt.innerHTML = '';
  mnt.appendChild(node);
}

Examples

Use with pre-processor (e.g. babel)

/** @jsx h */
var app = (
  <section>
    <h1>Test: <code>test</code></h1>
    <article className="post">
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc quis ornare velit.</p>
      <p>Nullam interdum, lorem non volutpat auctor, quam ante tempus massa, eget dignissim ligula erat non arcu.</p>
    </article>
  </section>
)

mount(document.getElementById("app"), app);

Without pre-processor

var app = h(
  'section',
  null,
  h('h1', null, 'Test: ', h('code', null, 'test')),
  h(
    'article',
    { className: 'post' },
    h('p', null, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc quis ornare velit.'),
    h(
      'p',
      null,
      'Nullam interdum, lorem non volutpat auctor, quam ante tempus massa, eget dignissim ligula erat non arcu.',
    ),
  ),
);

mount(document.getElementById('app'), app);

Stateless components

/** @jsx h */
(function (root) {
  function UnsafeHtml({ html }) {
    var div = (<i />);
    div.innerHTML = html;
    return div.childNodes;
  }

  function ExternalLink({ className, href, children }) {
    return (
      <a className={className} href={href} target="_blank">
        {children}
      </a>
    );
  }

  function Author({ author, uri }) {
    var AuthorTag = uri ? ExternalLink : "i";
    return (
      <AuthorTag className="author" href={uri}>
        {author || "无名氏"}
      </AuthorTag>
    );
  }

  function Comment({ website, author, uri, text }) {
    return (
      <div className="comment">
        <p>
          <Author className="author" author={author} uri={website} />
          (来源: <ExternalLink href={`https://jixun.moe` + uri}>{uri}</ExternalLink>)
        </p>
        <div className="body">
          <UnsafeHtml html={text} />
        </div>
      </div>
    );
  }

  function App({ comments }) {
    return (
      <div className="comments">
        {comments.map(comment => (
          <Comment {...comment} />
        ))}
      </div>
    );
  }

  var xhr = new XMLHttpRequest();
  xhr.open("GET", "/latest");
  xhr.onload = xhr.onerror = function () {
    var data;
    try {
      data = JSON.parse(xhr.responseText);
      mount(root, <App {...data} />);
    } catch (error) {
      root.textContent = "获取评论出错。";
    }
  }
  xhr.send();
})(document.getElementById("app"));

URL Highlight (Fragment + Stateless)

function Port({ port }) {
  if (port !== '') {
    return h('span', { className: 'port' }, ':' + port);
  }
}

function Domain({ domain }) {
  /** @type {string[]} */
  const ltdParts = domain.split('.');
  let rootDomainSegments = -1;

  // 如果后两个部分不超过 5 字符,则认为这是一个合法的二级域名
  // 如 co.jp、co.uk
  if (ltdParts.length > 2 && (ltdParts.at(-2) + ltdParts.at(-1)).length <= 5) {
    rootDomainSegments = -3;
  } else if (ltdParts.length > 1) {
    rootDomainSegments = -2;
  }

  const subDomain = ltdParts.slice(0, rootDomainSegments).join('.');
  const rootDomain = ltdParts.slice(rootDomainSegments).join('.');
  return h(
    h.Fragment,
    null,
    h('span', null, subDomain),
    subDomain && '.',
    h('span', { style: { color: '#000' } }, rootDomain),
  );
}

function Credential({ username, password }) {
  return h(
    h.Fragment,
    null,
    h('span', { style: { color: 'red' } }, username),
    password && h(h.Fragment, null, password && ':', h('span', { style: { color: 'blue' } }, password)),
    (username || password) && '@',
  );
}

function UrlRender({ url }) {
  return h(
    'span',
    { style: { color: '#777' } },
    h('span', null, url.protocol),
    '//',
    h(Credential, { username: url.username, password: url.password }),
    h(Domain, { domain: url.hostname }),
    h(Port, { port: url.port }),
    h('span', null, url.pathname),
    h('span', null, url.search),
    h('span', null, url.hash),
  );
}

const url = new URL('https://jixun:[email protected]/path?query#hash');
mount(document.querySelector('#root'), h(UrlRender, { url }));
Read more »

100% Orange Juice - Resource decryption & extraction (cli)

Expected to work with XP but not tested.

Supported resource type:

  • .dat decryption
  • ZIP archive pretending as a .dat file (e.g. animation.pak)
  • Packed ogg files (e.g. bgm.pak)
  • Packed wav files (e.g. se.pak)

Usage:

100% Orange Pak decryptor v1.1
by: Jixun Moe<https://jixun.moe/>

This tool is provided "AS IS", without warranty of any kind,
  and commercial usage is strictly prohibited.

Usage:
  OrangeDecryptor <input> <output> [mode]

mode is the decryption mode; it can be one of the following:
  dat      Apply dat decryption. Note: Any file not recognised will fallback to this mode.
  zip      Extract file as zip to output(as directory), then apply dat decryption (if ending with .dat).
  ogg      Seperate audio file to different files; name pattern: [output]/[000].ogg
  wav      Extract WAV sound (Sound Effects & Voice) from pak archive.
  auto     Default; it will check the file header and perform action.

Download: Jixun Storage | Yandex

Read more »

Convert JSON data to TypeScript interfaces

An useful tool to quick convert JSON data to TypeScript interfaces.

All you need to do is to paste the data, click 点我转换(Click to Convert), and done!

Sample input:

{
  "url": "https://jixun.moe/",
  "posts": [
    { "title": "日记", "date": "2016.06.08" },
    { "title": "随笔", "date": "2016.06.09" }
  ],
  "last-update": 1465388410306
}

Sample output:

Read more »