First commit

This commit is contained in:
Pierre Hubert
2016-11-19 12:08:12 +01:00
commit 990540b2b9
4706 changed files with 931207 additions and 0 deletions

File diff suppressed because one or more lines are too long

1
tools/3rdparty/metrouicss/css/metro.min.css vendored Executable file

File diff suppressed because one or more lines are too long

BIN
tools/3rdparty/metrouicss/fonts/metro.eot vendored Executable file

Binary file not shown.

476
tools/3rdparty/metrouicss/fonts/metro.svg vendored Executable file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 327 KiB

BIN
tools/3rdparty/metrouicss/fonts/metro.ttf vendored Executable file

Binary file not shown.

BIN
tools/3rdparty/metrouicss/fonts/metro.woff vendored Executable file

Binary file not shown.

12179
tools/3rdparty/metrouicss/fonts/selection.json vendored Executable file

File diff suppressed because one or more lines are too long

12
tools/assets/css/home_tools.css Executable file
View File

@@ -0,0 +1,12 @@
/* Feuille de styles pour l'acceuil des outils pour Comunic */
.tools_container {
margin: auto;
margin-top: 20px;
width: 385px;
text-align: justify;
}
.tools_container .button {
width: 385px;
}

BIN
tools/assets/img/favicon.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

40
tools/index.php Executable file
View File

@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head>
<title>Outils</title>
<!-- Styles CSS de la page -->
<link type="text/css" rel="stylesheet" href="assets/css/home_tools.css" />
</head>
<body>
<?php include('menu.php'); ?>
<div class="tools_container">
<p>Les outils ci-dessous sont des outils qui pour la plupart ne n&eacute;cessitent pas de compte Comunic mais qui pourrait vous rendre service notamment dans l'utilisation du r&eacute;seau social.</p>
<a class="button command-button" href="nobin">
<span class="icon mif-lock"></span>
ZeroBin
<small>Vous permet de transmettre des messages crypt&eacute;s.</small>
</a>
<a class="button command-button" href="speaker">
<span class="icon mif-volume-high"></span>
Speaker.js
<small>Logiciel de synth&egrave;se vocale web.</small>
</a>
<a class="button command-button" href="../minifyurl/">
<span class="icon mif-shrink2"></span>
MinifyURL
<small>Outil de r&eacute;duction d'URL.</small>
</a>
<a class="button command-button" href="svgedit">
<span class="icon mif-paint"></span>
SVGEdit
<small>Logiciel d'&eacute;dition d'images vectorielles web (images qui peuvent &ecirc;tres agrandies &agrave; l'infini).</small>
</a>
</div>
</body>
</html>

24
tools/menu.php Executable file
View File

@@ -0,0 +1,24 @@
<?php
//Inclusion de la configuration du site
include((isset($sub_folder) ? "../" : "").'../inc/config/config.php');
?>
<!-- Icone du site -->
<link rel="icon" type="image/vnd.microsoft.icon" href="<?php echo $urlsite;?>tool/assets/img/favicon.ico" />
<link rel="shortcut icon" type="image/x-icon" href="<?php echo $urlsite;?>tools/assets/img/favicon.ico" />
<!-- Fin de: Icone du site -->
<!-- Metro UI CSS 3.0 -->
<link type="text/css" rel="stylesheet" href="<?php echo $urlsite;?>tools/3rdparty/metrouicss/css/metro.min.css" />
<link type="text/css" rel="stylesheet" href="<?php echo $urlsite;?>tools/3rdparty/metrouicss/css/metro-icons.min.css" />
<!-- Barre de menu -->
<div class="app-bar" data-role="appbar">
<a class="app-bar-element" href="<?php echo $urlsite; ?>tools/"><span class="mif-tools"></span> Outils</a>
<span class="app-bar-divider"></span>
<a class="app-bar-element" href="<?php echo $urlsite; ?>tools/nobin"><span class="mif-lock"></span> ZeroBin</a>
<a class="app-bar-element" href="<?php echo $urlsite; ?>tools/speaker"><span class="mif-volume-high"></span> Speaker.js</a>
<a class="app-bar-element" href="<?php echo $urlsite; ?>tools/svgedit"><span class="mif-paint"></span> SVGEdit</a>
<a class="app-bar-element place-right" href="<?php echo $urlsite; ?>" target="_blank">Comunic</a>
</div>

39
tools/nobin/README.md Executable file
View File

@@ -0,0 +1,39 @@
ZeroBin 0.19 Alpha for Comunic
==== THIS IS ALPHA SOFTWARE - USE AT YOUR OWN RISKS ====
ZeroBin is a minimalist, opensource online pastebin where the server
has zero knowledge of pasted data. Data is encrypted/decrypted in the
browser using 256 bits AES.
More information on the project page:
http://sebsauvage.net/wiki/doku.php?id=php:zerobin
------------------------------------------------------------------------------
Copyright (c) 2012 Sébastien SAUVAGE (sebsauvage.net)
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from
the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must
not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
------------------------------------------------------------------------------
Notice: Some parts of code may have been modified to integrate the projects to
the tools of Comunic. However, cryptographic parts haven't been affected. Your
privacy remains respected.

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,312 @@
/*
ZeroBin 0.19 - http://sebsauvage.net/wiki/doku.php?id=php:zerobin
Code source modifié pour COMUNIC par PIERRE HUBERT le 13 avril 2016
*/
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 0.8em;
margin-bottom:15px;
padding-left:60px; padding-right:60px;
}
a { color:#0F388F; }
h1 {
font-size:3.5em;
font-weight:700;
color:#000;
position:relative;
display:inline;
cursor:pointer;
}
h1:before {
content:attr(title);
position:absolute;
color:rgba(255,255,255,0.15);
top:1px;
left:1px;
cursor:pointer;
}
h2 {
color:#000;
font-size:1em;
display:inline;
font-style:italic;
font-weight:bold;
position:relative;
bottom:8px;}
h3 {
color:#94a3b4;
font-size:0.7em;
display:inline;
position:relative;
bottom:8px;}
#aboutbox {
font-size:0.85em;
color: #94a3b4;
padding: 4px 8px 4px 16px;
position:relative;
top:10px;
border-left: 2px solid #94a3b4;
float:right;
width:60%;
}
div#aboutbox a { color: #94a3b4; }
textarea#message,div#cleartext,.replymessage, code {
clear:both;
color:black;
background-color:#fff;
white-space:pre-wrap;
font-family:Consolas,"Lucida Console","DejaVu Sans Mono",Monaco,monospace;
font-size:9pt;
border: 1px solid #28343F;
padding:5px;
box-sizing:border-box;
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
-ms-box-sizing:border-box;
-o-box-sizing:border-box;
width:100%;
}
div#status {
clear:both;
padding:5px 10px;
}
div#pasteresult a { color:white; }
div#pasteresult button { margin-left:11px }
div#toolbar, div#status { margin-bottom:5px; }
#copyhint { font-size:8pt; }
button,.button,div#expiration {
color:#fff;
background-repeat:no-repeat;
background-position:center left;
padding:4px 8px;
font-size:1em;
margin-right:5px;
display:inline;
}
/* Ajouté pour Comunic */
div#expiration select {
width: auto;
}
.pastelink {
text-align: center;
font-size: 125%;
}
/* -- Fin de la zone d'ajout -- */
div#expiration, div#rawtextbutton, div#burnafterreadingoption, div#opendisc, div#syntaxcoloringoption {
padding:6px 8px;
margin:0px 5px 0px 0px;;
position: relative;
bottom:1px;
}
div#remainingtime {
color: #94a3b4;
display:inline;
font-size:0.85em;
}
.foryoureyesonly {
color: #F00 !important; /* Modifié pour Comunic */
font-size: 1em !important;
font-weight:bold !important;
}
button#newbutton { float:right; margin-right:0px;margin-bottom:5px; display:inline; }
input { color:#777; font-size:1em; padding:6px; border: 1px solid #28343F; }
.nonworking {
background-color:#fff;
color:#000;
width:100%;
text-align:center;
font-weight:bold;
font-size:10pt;
-webkit-border-radius:4px;
-moz-border-radius:4px;
border-radius:4px;
padding:5px;
}
div#ienotice {
background-color:#7E98AF;
color:#000;
font-size:0.85em;
padding:3px 5px;
text-align:center;
-webkit-border-radius:4px;
-moz-border-radius:4px;
border-radius:4px;
display:none;
}
div#ienotice a {
color:black;
}
div#oldienotice {
display:none;
}
.errorMessage {
background-color:#FF7979 !important;
color:#FF0;
}
/* --- discussion related CSS ------- */
div#discussion { /* Discussion container */
margin-top:20px;
width:100%;
margin-left:-30px;
min-width:200px;
}
h4 {
font-size:1.2em;
color: #94A3B4;
font-style:italic;
font-weight:bold;
position:relative;
margin-left:30px;
}
div.comment /* One single reply */
{
background-color:#CECED6;
color:#000;
white-space:pre-wrap;
font-family:Consolas,"Lucida Console","DejaVu Sans Mono",Monaco,monospace;
font-size:9pt;
border-left: 1px solid #859AAE;
border-top: 1px solid #859AAE;
padding:5px 0px 5px 5px;
margin-left:30px;
-moz-box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
-webkit-box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
min-width:200px;
overflow:auto;
}
/* FIXME: Add min-width */
div.reply {
margin: 5px 0px 0px 30px;
}
div#replystatus {
display:inline;
padding:1px 7px;
font-family: Arial, Helvetica, sans-serif;
}
div.comment button {
color:#446;
background-color:#aab;
background-repeat:no-repeat;
background-position:center left;
padding:0px 2px;
font-size:0.73em;
margin: 3px 5px 3px 0px;
display:inline;
background-image: linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -o-linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -moz-linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -webkit-linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -ms-linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #aab), color-stop(1, #ccc));
border: 1px solid #ccd;
-moz-box-shadow: inset 0px 1px 2px #ddd;
-webkit-box-shadow: inset 0px 1px 2px #fff;
box-shadow: inset 0px 1px 2px #eee;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
-moz-background-clip: padding; -webkit-background-clip: padding-box; background-clip: padding-box;
}
div.comment button:hover {
background-image: linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -o-linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -moz-linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -webkit-linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -ms-linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccd), color-stop(1, #fff));
}
div.comment button:active {
background-image: linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -o-linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -moz-linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -webkit-linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -ms-linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(1, #889));
position:relative;
top:1px;
}
div.comment input {
padding:2px;
}
textarea#replymessage {
margin-top:5px;
}
div.commentmeta {
color: #fff;
background-color:#8EA0B2;
margin-bottom:3px;
padding:0px 0px 0px 3px;
}
span.commentdate {
color: #BFCEDE;
}
img.vizhash {
width:16px;
height:16px;
position:relative;
top:2px;
left:-3px;
}
pre a {
color:#58A5B4;
}
pre a:hover {
color:#64B9C6;
}
/* Added for Comunic */
.info-zerobin {
position: absolute !important;
width: 245px !important;
text-align: justify;
right: 0px;
height: 190px !important;
z-index: 2;
}

View File

@@ -0,0 +1,312 @@
/*
ZeroBin 0.19 - http://sebsauvage.net/wiki/doku.php?id=php:zerobin
Code source modifié pour COMUNIC par PIERRE HUBERT le 13 avril 2016
*/
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 0.8em;
margin-bottom:15px;
padding-left:60px; padding-right:60px;
}
a { color:#0F388F; }
h1 {
font-size:3.5em;
font-weight:700;
color:#000;
position:relative;
display:inline;
cursor:pointer;
}
h1:before {
content:attr(title);
position:absolute;
color:rgba(255,255,255,0.15);
top:1px;
left:1px;
cursor:pointer;
}
h2 {
color:#000;
font-size:1em;
display:inline;
font-style:italic;
font-weight:bold;
position:relative;
bottom:8px;}
h3 {
color:#94a3b4;
font-size:0.7em;
display:inline;
position:relative;
bottom:8px;}
#aboutbox {
font-size:0.85em;
color: #94a3b4;
padding: 4px 8px 4px 16px;
position:relative;
top:10px;
border-left: 2px solid #94a3b4;
float:right;
width:60%;
}
div#aboutbox a { color: #94a3b4; }
textarea#message,div#cleartext,.replymessage, code {
clear:both;
color:black;
background-color:#fff;
white-space:pre-wrap;
font-family:Consolas,"Lucida Console","DejaVu Sans Mono",Monaco,monospace;
font-size:9pt;
border: 1px solid #28343F;
padding:5px;
box-sizing:border-box;
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
-ms-box-sizing:border-box;
-o-box-sizing:border-box;
width:100%;
}
div#status {
clear:both;
padding:5px 10px;
}
div#pasteresult a { color:white; }
div#pasteresult button { margin-left:11px }
div#toolbar, div#status { margin-bottom:5px; }
#copyhint { font-size:8pt; }
button,.button,div#expiration {
color:#fff;
background-repeat:no-repeat;
background-position:center left;
padding:4px 8px;
font-size:1em;
margin-right:5px;
display:inline;
}
/* Ajouté pour Comunic */
div#expiration select {
width: auto;
}
.pastelink {
text-align: center;
font-size: 125%;
}
/* -- Fin de la zone d'ajout -- */
div#expiration, div#rawtextbutton, div#burnafterreadingoption, div#opendisc, div#syntaxcoloringoption {
padding:6px 8px;
margin:0px 5px 0px 0px;;
position: relative;
bottom:1px;
}
div#remainingtime {
color: #94a3b4;
display:inline;
font-size:0.85em;
}
.foryoureyesonly {
color: #F00 !important; /* Modifié pour Comunic */
font-size: 1em !important;
font-weight:bold !important;
}
button#newbutton { float:right; margin-right:0px;margin-bottom:5px; display:inline; }
input { color:#777; font-size:1em; padding:6px; border: 1px solid #28343F; }
.nonworking {
background-color:#fff;
color:#000;
width:100%;
text-align:center;
font-weight:bold;
font-size:10pt;
-webkit-border-radius:4px;
-moz-border-radius:4px;
border-radius:4px;
padding:5px;
}
div#ienotice {
background-color:#7E98AF;
color:#000;
font-size:0.85em;
padding:3px 5px;
text-align:center;
-webkit-border-radius:4px;
-moz-border-radius:4px;
border-radius:4px;
display:none;
}
div#ienotice a {
color:black;
}
div#oldienotice {
display:none;
}
.errorMessage {
background-color:#FF7979 !important;
color:#FF0;
}
/* --- discussion related CSS ------- */
div#discussion { /* Discussion container */
margin-top:20px;
width:100%;
margin-left:-30px;
min-width:200px;
}
h4 {
font-size:1.2em;
color: #94A3B4;
font-style:italic;
font-weight:bold;
position:relative;
margin-left:30px;
}
div.comment /* One single reply */
{
background-color:#CECED6;
color:#000;
white-space:pre-wrap;
font-family:Consolas,"Lucida Console","DejaVu Sans Mono",Monaco,monospace;
font-size:9pt;
border-left: 1px solid #859AAE;
border-top: 1px solid #859AAE;
padding:5px 0px 5px 5px;
margin-left:30px;
-moz-box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
-webkit-box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
min-width:200px;
overflow:auto;
}
/* FIXME: Add min-width */
div.reply {
margin: 5px 0px 0px 30px;
}
div#replystatus {
display:inline;
padding:1px 7px;
font-family: Arial, Helvetica, sans-serif;
}
div.comment button {
color:#446;
background-color:#aab;
background-repeat:no-repeat;
background-position:center left;
padding:0px 2px;
font-size:0.73em;
margin: 3px 5px 3px 0px;
display:inline;
background-image: linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -o-linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -moz-linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -webkit-linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -ms-linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #aab), color-stop(1, #ccc));
border: 1px solid #ccd;
-moz-box-shadow: inset 0px 1px 2px #ddd;
-webkit-box-shadow: inset 0px 1px 2px #fff;
box-shadow: inset 0px 1px 2px #eee;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
-moz-background-clip: padding; -webkit-background-clip: padding-box; background-clip: padding-box;
}
div.comment button:hover {
background-image: linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -o-linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -moz-linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -webkit-linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -ms-linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccd), color-stop(1, #fff));
}
div.comment button:active {
background-image: linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -o-linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -moz-linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -webkit-linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -ms-linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(1, #889));
position:relative;
top:1px;
}
div.comment input {
padding:2px;
}
textarea#replymessage {
margin-top:5px;
}
div.commentmeta {
color: #fff;
background-color:#8EA0B2;
margin-bottom:3px;
padding:0px 0px 0px 3px;
}
span.commentdate {
color: #BFCEDE;
}
img.vizhash {
width:16px;
height:16px;
position:relative;
top:2px;
left:-3px;
}
pre a {
color:#58A5B4;
}
pre a:hover {
color:#64B9C6;
}
/* Ajouté pour Comunic */
.info-zerobin {
position: absolute !important;
width: 245px !important;
text-align: justify;
right: 0px;
height: 164px !important;
z-index: 2;
}

View File

@@ -0,0 +1,368 @@
/* ZeroBin 0.19 - http://sebsauvage.net/wiki/doku.php?id=php:zerobin */
/* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved.
Licensed under the BSD License. - http://yuilibrary.com/license/ */
html{color:#000;background:#FFF}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0}fieldset,img{border:0}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal}ol,ul{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}q:before,q:after{content:''}abbr,acronym{border:0;font-variant:normal}sup{vertical-align:text-top}sub{vertical-align:text-bottom}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit}input,textarea,select{*font-size:100%}legend{color:#000}
html {
background-color:#455463;
color:white;
min-height:100%;
background-image: linear-gradient(bottom, #0F1823 0%, #455463 100%);
background-image: -o-linear-gradient(bottom, #0F1823 0%, #455463 100%);
background-image: -moz-linear-gradient(bottom, #0F1823 0%, #455463 100%);
background-image: -webkit-linear-gradient(bottom, #0F1823 0%, #455463 100%);
background-image: -ms-linear-gradient(bottom, #0F1823 0%, #455463 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #0F1823), color-stop(1, #455463));
}
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 0.8em;
margin-bottom:15px;
padding-left:60px; padding-right:60px;
}
a { color:#0F388F; }
h1 {
font-size:3.5em;
font-weight:700;
color:#000;
position:relative;
display:inline;
cursor:pointer;
}
h1:before {
content:attr(title);
position:absolute;
color:rgba(255,255,255,0.15);
top:1px;
left:1px;
cursor:pointer;
}
h2 {
color:#000;
font-size:1em;
display:inline;
font-style:italic;
font-weight:bold;
position:relative;
bottom:8px;}
h3 {
color:#94a3b4;
font-size:0.7em;
display:inline;
position:relative;
bottom:8px;}
#aboutbox {
font-size:0.85em;
color: #94a3b4;
padding: 4px 8px 4px 16px;
position:relative;
top:10px;
border-left: 2px solid #94a3b4;
float:right;
width:60%;
}
div#aboutbox a { color: #94a3b4; }
textarea#message,div#cleartext,.replymessage, code {
clear:both;
color:black;
background-color:#fff;
white-space:pre-wrap;
font-family:Consolas,"Lucida Console","DejaVu Sans Mono",Monaco,monospace;
font-size:9pt;
border: 1px solid #28343F;
padding:5px;
box-sizing:border-box;
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
-ms-box-sizing:border-box;
-o-box-sizing:border-box;
width:100%;
}
div#status {
clear:both;
padding:5px 10px;
}
div#pasteresult {
background-color:#1F2833;
color:white;
padding:4px 12px;
clear:both;
-moz-box-shadow: inset 0px 2px 2px #000;
-webkit-box-shadow: inset 0px 2px 2px #000;
box-shadow: inset 0px 2px 5px #000;
}
div#pasteresult a { color:white; }
div#pasteresult button { margin-left:11px }
div#deletelink { float:right; }
div#toolbar, div#status { margin-bottom:5px; }
#copyhint { color: #666; font-size:8pt; }
button,.button,div#expiration {
color:#fff;
background-color:#323B47;
background-repeat:no-repeat;
background-position:center left;
padding:4px 8px;
font-size:1em;
margin-right:5px;
display:inline;
background-image: linear-gradient(bottom, #323B47 0%, #51606E 100%);
background-image: -o-linear-gradient(bottom, #323B47 0%, #51606E 100%);
background-image: -moz-linear-gradient(bottom, #323B47 0%, #51606E 100%);
background-image: -webkit-linear-gradient(bottom, #323B47 0%, #51606E 100%);
background-image: -ms-linear-gradient(bottom, #323B47 0%, #51606E 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #323B47), color-stop(1, #51606E));
border: 1px solid #28343F;
-moz-box-shadow: inset 0px 1px 2px #647384;
-webkit-box-shadow: inset 0px 1px 2px #647384;
box-shadow: inset 0px 1px 2px #647384;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
-moz-background-clip: padding; -webkit-background-clip: padding-box; background-clip: padding-box;
}
button:hover {
background-image: linear-gradient(bottom, #424B57 0%, #61707E 100%);
background-image: -o-linear-gradient(bottom, #424B57 0%, #61707E 100%);
background-image: -moz-linear-gradient(bottom, #424B57 0%, #61707E 100%);
background-image: -webkit-linear-gradient(bottom, #424B57 0%, #61707E 100%);
background-image: -ms-linear-gradient(bottom, #424B57 0%, #61707E 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #424B57), color-stop(1, #61707E));
}
button:active {
background-image: linear-gradient(bottom, #51606E 0%, #323B47 100%);
background-image: -o-linear-gradient(bottom, #51606E 0%, #323B47 100%);
background-image: -moz-linear-gradient(bottom, #51606E 0%, #323B47 100%);
background-image: -webkit-linear-gradient(bottom, #51606E 0%, #323B47 100%);
background-image: -ms-linear-gradient(bottom, #51606E 0%, #323B47 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #51606E), color-stop(1, #323B47));
position:relative;
top:1px;
}
button:disabled, .buttondisabled {
background:#ccc;
color:#888;
top:0px;
}
button img {
margin-right:8px;
position:relative;
top:2px;
}
div#expiration, div#rawtextbutton, div#burnafterreadingoption, div#opendisc, div#syntaxcoloringoption {
background-color:#414D5A;
padding:6px 8px;
margin:0px 5px 0px 0px;;
position: relative;
bottom:1px; /* WTF ? Why is this shifted by 1 pixel ? */
}
div#expiration select {
color:#eee;
background: transparent;
border: none;
}
div#expiration select option {
color:#eee;
background: #414D5A;
background-color:#414D5A;
}
div#remainingtime {
color: #94a3b4;
display:inline;
font-size:0.85em;
}
.foryoureyesonly {
color: yellow !important;
font-size: 1em !important;
font-weight:bold !important;
}
button#newbutton { float:right; margin-right:0px;margin-bottom:5px; display:inline; }
input { color:#777; font-size:1em; padding:6px; border: 1px solid #28343F; }
.nonworking {
background-color:#fff;
color:#000;
width:100%;
text-align:center;
font-weight:bold;
font-size:10pt;
-webkit-border-radius:4px;
-moz-border-radius:4px;
border-radius:4px;
padding:5px;
}
div#ienotice {
background-color:#7E98AF;
color:#000;
font-size:0.85em;
padding:3px 5px;
text-align:center;
-webkit-border-radius:4px;
-moz-border-radius:4px;
border-radius:4px;
display:none;
}
div#ienotice a {
color:black;
}
div#oldienotice {
display:none;
}
.errorMessage {
background-color:#FF7979 !important;
color:#FF0;
}
/* --- discussion related CSS ------- */
div#discussion { /* Discussion container */
margin-top:20px;
width:100%;
margin-left:-30px;
min-width:200px;
}
h4 {
font-size:1.2em;
color: #94A3B4;
font-style:italic;
font-weight:bold;
position:relative;
margin-left:30px;
}
div.comment /* One single reply */
{
background-color:#CECED6;
color:#000;
white-space:pre-wrap;
font-family:Consolas,"Lucida Console","DejaVu Sans Mono",Monaco,monospace;
font-size:9pt;
border-left: 1px solid #859AAE;
border-top: 1px solid #859AAE;
padding:5px 0px 5px 5px;
margin-left:30px;
-moz-box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
-webkit-box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
min-width:200px;
overflow:auto;
}
/* FIXME: Add min-width */
div.reply {
margin: 5px 0px 0px 30px;
}
div#replystatus {
display:inline;
padding:1px 7px;
font-family: Arial, Helvetica, sans-serif;
}
div.comment button {
color:#446;
background-color:#aab;
background-repeat:no-repeat;
background-position:center left;
padding:0px 2px;
font-size:0.73em;
margin: 3px 5px 3px 0px;
display:inline;
background-image: linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -o-linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -moz-linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -webkit-linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -ms-linear-gradient(bottom, #aab 0%, #ccc 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #aab), color-stop(1, #ccc));
border: 1px solid #ccd;
-moz-box-shadow: inset 0px 1px 2px #ddd;
-webkit-box-shadow: inset 0px 1px 2px #fff;
box-shadow: inset 0px 1px 2px #eee;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
-moz-background-clip: padding; -webkit-background-clip: padding-box; background-clip: padding-box;
}
div.comment button:hover {
background-image: linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -o-linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -moz-linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -webkit-linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -ms-linear-gradient(bottom, #ccd 0%, #fff 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccd), color-stop(1, #fff));
}
div.comment button:active {
background-image: linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -o-linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -moz-linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -webkit-linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -ms-linear-gradient(bottom, #fff 0%, #889 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(1, #889));
position:relative;
top:1px;
}
div.comment input {
padding:2px;
}
textarea#replymessage {
margin-top:5px;
}
div.commentmeta {
color: #fff;
background-color:#8EA0B2;
margin-bottom:3px;
padding:0px 0px 0px 3px;
}
span.commentdate {
color: #BFCEDE;
}
img.vizhash {
width:16px;
height:16px;
position:relative;
top:2px;
left:-3px;
}
pre a {
color:#58A5B4;
}
pre a:hover {
color:#64B9C6;
}

2
tools/nobin/data/index.php Executable file
View File

@@ -0,0 +1,2 @@
<?php
//Silent is gold

1
tools/nobin/data/salt.php Executable file
View File

@@ -0,0 +1 @@
<?php /* |456075172eea48c377992785331b95fe34ab80de1ca96f935678b36a6ca650107899fa2314f7385f1523e0267987727a38b6d09275c94b36bf563477bc522a5| */ ?>

View File

@@ -0,0 +1,6 @@
<?php
$GLOBALS['trafic_limiter']=array (
'192.168.1.24' => 1460550247,
'127.0.0.1' => 1477725456,
);
?>

BIN
tools/nobin/img/busy.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 B

BIN
tools/nobin/img/icon_clone.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

BIN
tools/nobin/img/icon_new.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

BIN
tools/nobin/img/icon_raw.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

BIN
tools/nobin/img/icon_send.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

429
tools/nobin/index.php Executable file
View File

@@ -0,0 +1,429 @@
<?php
/*
ZeroBin - a zero-knowledge paste bin
Please see project page: http://sebsauvage.net/wiki/doku.php?id=php:zerobin
*/
$VERSION='Alpha 0.19';
if (version_compare(PHP_VERSION, '5.2.6') < 0) die('ZeroBin requiert php 5.2.6 ou une version supérieure pour fonctionner. Désolé.');
require_once "lib/serversalt.php";
require_once "lib/vizhash_gd_zero.php";
// In case stupid admin has left magic_quotes enabled in php.ini:
if (get_magic_quotes_gpc())
{
function stripslashes_deep($value) { $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); return $value; }
$_POST = array_map('stripslashes_deep', $_POST);
$_GET = array_map('stripslashes_deep', $_GET);
$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
}
// trafic_limiter : Make sure the IP address makes at most 1 request every 10 seconds.
// Will return false if IP address made a call less than 10 seconds ago.
function trafic_limiter_canPass($ip)
{
$tfilename='./data/trafic_limiter.php';
if (!is_file($tfilename))
{
file_put_contents($tfilename,"<?php\n\$GLOBALS['trafic_limiter']=array();\n?>", LOCK_EX);
chmod($tfilename,0705);
}
require $tfilename;
$tl=$GLOBALS['trafic_limiter'];
if (!empty($tl[$ip]) && ($tl[$ip]+10>=time()))
{
return false;
// FIXME: purge file of expired IPs to keep it small
}
$tl[$ip]=time();
file_put_contents($tfilename, "<?php\n\$GLOBALS['trafic_limiter']=".var_export($tl,true).";\n?>", LOCK_EX);
return true;
}
// Constant time string comparison.
// (Used to deter time attacks on hmac checking. See section 2.7 of https://defuse.ca/audits/zerobin.htm)
function slow_equals($a, $b)
{
$diff = strlen($a) ^ strlen($b);
for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
{
$diff |= ord($a[$i]) ^ ord($b[$i]);
}
return $diff === 0;
}
/* Convert paste id to storage path.
The idea is to creates subdirectories in order to limit the number of files per directory.
(A high number of files in a single directory can slow things down.)
eg. "f468483c313401e8" will be stored in "data/f4/68/f468483c313401e8"
High-trafic websites may want to deepen the directory structure (like Squid does).
eg. input 'e3570978f9e4aa90' --> output 'data/e3/57/'
*/
function dataid2path($dataid)
{
return 'data/'.substr($dataid,0,2).'/'.substr($dataid,2,2).'/';
}
/* Convert paste id to discussion storage path.
eg. 'e3570978f9e4aa90' --> 'data/e3/57/e3570978f9e4aa90.discussion/'
*/
function dataid2discussionpath($dataid)
{
return dataid2path($dataid).$dataid.'.discussion/';
}
// Checks if a json string is a proper SJCL encrypted message.
// False if format is incorrect.
function validSJCL($jsonstring)
{
$accepted_keys=array('iv','v','iter','ks','ts','mode','adata','cipher','salt','ct');
// Make sure content is valid json
$decoded = json_decode($jsonstring);
if ($decoded==null) return false;
$decoded = (array)$decoded;
// Make sure required fields are present
foreach($accepted_keys as $k)
{
if (!array_key_exists($k,$decoded)) { return false; }
}
// Make sure some fields are base64 data
if (base64_decode($decoded['iv'],$strict=true)==null) { return false; }
if (base64_decode($decoded['salt'],$strict=true)==null) { return false; }
if (base64_decode($decoded['cipher'],$strict=true)==null) { return false; }
// Make sure no additionnal keys were added.
if (count(array_intersect(array_keys($decoded),$accepted_keys))!=10) { return false; }
// Reject data if entropy is too low
$ct = base64_decode($decoded['ct'], $strict=true);
if (strlen($ct) > strlen(gzdeflate($ct))) return false;
// Make sure some fields have a reasonable size.
if (strlen($decoded['iv'])>24) return false;
if (strlen($decoded['salt'])>14) return false;
return true;
}
// Delete a paste and its discussion.
// Input: $pasteid : the paste identifier.
function deletePaste($pasteid)
{
// Delete the paste itself
unlink(dataid2path($pasteid).$pasteid);
// Delete discussion if it exists.
$discdir = dataid2discussionpath($pasteid);
if (is_dir($discdir))
{
// Delete all files in discussion directory
$dhandle = opendir($discdir);
while (false !== ($filename = readdir($dhandle)))
{
if (is_file($discdir.$filename)) unlink($discdir.$filename);
}
closedir($dhandle);
// Delete the discussion directory.
rmdir($discdir);
}
}
if (!empty($_POST['data'])) // Create new paste/comment
{
/* POST contains:
data (mandatory) = json encoded SJCL encrypted text (containing keys: iv,salt,ct)
All optional data will go to meta information:
expire (optional) = expiration delay (never,5min,10min,1hour,1day,1week,1month,1year,burn) (default:never)
opendiscusssion (optional) = is the discussion allowed on this paste ? (0/1) (default:0)
syntaxcoloring (optional) = should this paste use syntax coloring when displaying.
nickname (optional) = son encoded SJCL encrypted text nickname of author of comment (containing keys: iv,salt,ct)
parentid (optional) = in discussion, which comment this comment replies to.
pasteid (optional) = in discussion, which paste this comment belongs to.
*/
header('Content-type: application/json');
$error = false;
// Create storage directory if it does not exist.
if (!is_dir('data'))
{
mkdir('data',0705);
file_put_contents('data/.htaccess',"Allow from none\nDeny from all\n", LOCK_EX);
}
// Make sure last paste from the IP address was more than 10 seconds ago.
if (!trafic_limiter_canPass($_SERVER['REMOTE_ADDR']))
{ echo json_encode(array('status'=>1,'message'=>'Veuillez patienter 10 secondes entre chaque message sil vous plaît.')); exit; }
// Make sure content is not too big.
$data = $_POST['data'];
if (strlen($data)>2000000)
{ echo json_encode(array('status'=>1,'message'=>'Le contenu est limité à 2 Mb de données chiffrées.')); exit; }
// Make sure format is correct.
if (!validSJCL($data))
{ echo json_encode(array('status'=>1,'message'=>'Données incorrectes.')); exit; }
// Read additional meta-information.
$meta=array();
// Read expiration date
if (!empty($_POST['expire']))
{
$expire=$_POST['expire'];
if ($expire=='5min') $meta['expire_date']=time()+5*60;
elseif ($expire=='10min') $meta['expire_date']=time()+10*60;
elseif ($expire=='1hour') $meta['expire_date']=time()+60*60;
elseif ($expire=='1day') $meta['expire_date']=time()+24*60*60;
elseif ($expire=='1week') $meta['expire_date']=time()+7*24*60*60;
elseif ($expire=='1month') $meta['expire_date']=time()+30*24*60*60; // Well this is not *exactly* one month, it's 30 days.
elseif ($expire=='1year') $meta['expire_date']=time()+365*24*60*60;
}
// Destroy the paste when it is read.
if (!empty($_POST['burnafterreading']))
{
$burnafterreading = $_POST['burnafterreading'];
if ($burnafterreading!='0' && $burnafterreading!='1') { $error=true; }
if ($burnafterreading!='0') { $meta['burnafterreading']=true; }
}
// Read open discussion flag
if (!empty($_POST['opendiscussion']))
{
$opendiscussion = $_POST['opendiscussion'];
if ($opendiscussion!='0' && $opendiscussion!='1') { $error=true; }
if ($opendiscussion!='0') { $meta['opendiscussion']=true; }
}
// Should we use syntax coloring when displaying ?
if (!empty($_POST['syntaxcoloring']))
{
$syntaxcoloring = $_POST['syntaxcoloring'];
if ($syntaxcoloring!='0' && $syntaxcoloring!='1') { $error=true; }
if ($syntaxcoloring!='0') { $meta['syntaxcoloring']=true; }
}
// You can't have an open discussion on a "Burn after reading" paste:
if (isset($meta['burnafterreading'])) unset($meta['opendiscussion']);
// Optional nickname for comments
if (!empty($_POST['nickname']))
{
$nick = $_POST['nickname'];
if (!validSJCL($nick))
{
$error=true;
}
else
{
$meta['nickname']=$nick;
// Generation of the anonymous avatar (Vizhash):
// If a nickname is provided, we generate a Vizhash.
// (We assume that if the user did not enter a nickname, he/she wants
// to be anonymous and we will not generate the vizhash.)
$vz = new vizhash16x16();
$pngdata = $vz->generate($_SERVER['REMOTE_ADDR']);
if ($pngdata!='') $meta['vizhash'] = 'data:image/png;base64,'.base64_encode($pngdata);
// Once the avatar is generated, we do not keep the IP address, nor its hash.
}
}
if ($error)
{
echo json_encode(array('status'=>1,'message'=>'Données incorrectes.'));
exit;
}
// Add post date to meta.
$meta['postdate']=time();
// We just want a small hash to avoid collisions: Half-MD5 (64 bits) will do the trick.
$dataid = substr(hash('md5',$data),0,16);
$is_comment = (!empty($_POST['parentid']) && !empty($_POST['pasteid'])); // Is this post a comment ?
$storage = array('data'=>$data);
if (count($meta)>0) $storage['meta'] = $meta; // Add meta-information only if necessary.
if ($is_comment) // The user posts a comment.
{
$pasteid = $_POST['pasteid'];
$parentid = $_POST['parentid'];
if (!preg_match('/\A[a-f\d]{16}\z/',$pasteid)) { echo json_encode(array('status'=>1,'message'=>'Données incorrectes.')); exit; }
if (!preg_match('/\A[a-f\d]{16}\z/',$parentid)) { echo json_encode(array('status'=>1,'message'=>'Données incorrectes.')); exit; }
unset($storage['expire_date']); // Comment do not expire (it's the paste that expires)
unset($storage['opendiscussion']);
unset($storage['syntaxcoloring']);
// Make sure paste exists.
$storagedir = dataid2path($pasteid);
if (!is_file($storagedir.$pasteid)) { echo json_encode(array('status'=>1,'message'=>'Données incorrectes.')); exit; }
// Make sure the discussion is opened in this paste.
$paste=json_decode(file_get_contents($storagedir.$pasteid));
if (!$paste->meta->opendiscussion) { echo json_encode(array('status'=>1,'message'=>'Données incorrectes.')); exit; }
$discdir = dataid2discussionpath($pasteid);
$filename = $pasteid.'.'.$dataid.'.'.$parentid;
if (!is_dir($discdir)) mkdir($discdir,$mode=0705,$recursive=true);
if (is_file($discdir.$filename)) // Oups... improbable collision.
{
echo json_encode(array('status'=>1,'message'=>'Vous navez pas de chance. Essayez à nouveau.'));
exit;
}
file_put_contents($discdir.$filename,json_encode($storage), LOCK_EX);
echo json_encode(array('status'=>0,'id'=>$dataid)); // 0 = no error
exit;
}
else // a standard paste.
{
$storagedir = dataid2path($dataid);
if (!is_dir($storagedir)) mkdir($storagedir,$mode=0705,$recursive=true);
if (is_file($storagedir.$dataid)) // Oups... improbable collision.
{
echo json_encode(array('status'=>1,'message'=>'Vous navez pas de chance. Essayez à nouveau.'));
exit;
}
// New paste
file_put_contents($storagedir.$dataid,json_encode($storage), LOCK_EX);
// Generate the "delete" token.
// The token is the hmac of the pasteid signed with the server salt.
// The paste can be delete by calling http://myserver.com/zerobin/?pasteid=<pasteid>&deletetoken=<deletetoken>
$deletetoken = hash_hmac('sha1', $dataid , getServerSalt());
echo json_encode(array('status'=>0,'id'=>$dataid,'deletetoken'=>$deletetoken)); // 0 = no error
exit;
}
echo json_encode(array('status'=>1,'message'=>'Erreur du serveur.'));
exit;
}
/* Process a paste deletion request.
Returns an array ('',$ERRORMESSAGE,$STATUS)
*/
function processPasteDelete($pasteid,$deletetoken)
{
if (preg_match('/\A[a-f\d]{16}\z/',$pasteid)) // Is this a valid paste identifier ?
{
$filename = dataid2path($pasteid).$pasteid;
if (!is_file($filename)) // Check that paste exists.
{
return array('','Ce texte nexiste pas, il a expiré ou a été supprimé.','');
}
}
else
{
return array('','Données incorrectes.','');
}
if (!slow_equals($deletetoken, hash_hmac('sha1', $pasteid , getServerSalt()))) // Make sure token is valid.
{
return array('','Mauvais code de suppression. Le texte na pu être supprimé.','');
}
// Paste exists and deletion token is valid: Delete the paste.
deletePaste($pasteid);
return array('','','Texte a bien été supprimé.');
}
/* Process a paste fetch request.
Returns an array ($CIPHERDATA,$ERRORMESSAGE,$STATUS)
*/
function processPasteFetch($pasteid)
{
if (preg_match('/\A[a-f\d]{16}\z/',$pasteid)) // Is this a valid paste identifier ?
{
$filename = dataid2path($pasteid).$pasteid;
if (!is_file($filename)) // Check that paste exists.
{
return array('','Ce texte nexiste pas, il a expiré ou a été supprimé.','');
}
}
else
{
return array('','Données incorrectes.','');
}
// Get the paste itself.
$paste=json_decode(file_get_contents($filename));
// See if paste has expired.
if (isset($paste->meta->expire_date) && $paste->meta->expire_date<time())
{
deletePaste($pasteid); // Delete the paste
return array('','Ce texte nexiste pas, il a expiré ou a été supprimé.','');
}
// We kindly provide the remaining time before expiration (in seconds)
if (property_exists($paste->meta, 'expire_date')) $paste->meta->remaining_time = $paste->meta->expire_date - time();
$messages = array($paste); // The paste itself is the first in the list of encrypted messages.
// If it's a discussion, get all comments.
if (property_exists($paste->meta, 'opendiscussion') && $paste->meta->opendiscussion)
{
$comments=array();
$datadir = dataid2discussionpath($pasteid);
if (!is_dir($datadir)) mkdir($datadir,$mode=0705,$recursive=true);
$dhandle = opendir($datadir);
while (false !== ($filename = readdir($dhandle)))
{
if (is_file($datadir.$filename))
{
$comment=json_decode(file_get_contents($datadir.$filename));
// Filename is in the form pasteid.commentid.parentid:
// - pasteid is the paste this reply belongs to.
// - commentid is the comment identifier itself.
// - parentid is the comment this comment replies to (It can be pasteid)
$items=explode('.',$filename);
$comment->meta->commentid=$items[1]; // Add some meta information not contained in file.
$comment->meta->parentid=$items[2];
$comments[$comment->meta->postdate]=$comment; // Store in table
}
}
closedir($dhandle);
ksort($comments); // Sort comments by date, oldest first.
$messages = array_merge($messages, $comments);
}
$CIPHERDATA = json_encode($messages);
// If the paste was meant to be read only once, delete it.
if (property_exists($paste->meta, 'burnafterreading') && $paste->meta->burnafterreading) deletePaste($pasteid);
return array($CIPHERDATA,'','');
}
$CIPHERDATA='';
$ERRORMESSAGE='';
$STATUS='';
if (!empty($_GET['deletetoken']) && !empty($_GET['pasteid'])) // Delete an existing paste
{
list ($CIPHERDATA, $ERRORMESSAGE, $STATUS) = processPasteDelete($_GET['pasteid'],$_GET['deletetoken']);
}
else if (!empty($_SERVER['QUERY_STRING'])) // Return an existing paste.
{
list ($CIPHERDATA, $ERRORMESSAGE, $STATUS) = processPasteFetch($_SERVER['QUERY_STRING']);
}
require_once "lib/rain.tpl.class.php";
header('Content-Type: text/html; charset=utf-8');
$page = new RainTPL;
$page->assign('CIPHERDATA',htmlspecialchars($CIPHERDATA,ENT_NOQUOTES)); // We escape it here because ENT_NOQUOTES can't be used in RainTPL templates.
$page->assign('VERSION',$VERSION);
$page->assign('ERRORMESSAGE',$ERRORMESSAGE);
$page->assign('STATUS',$STATUS);
$page->draw('page');
?>

237
tools/nobin/js/base64.js Executable file
View File

@@ -0,0 +1,237 @@
/*
* $Id: base64.js,v 1.7 2012/08/23 10:30:18 dankogai Exp dankogai $
*
* Licensed under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*
* References:
* http://en.wikipedia.org/wiki/Base64
*/
(function(global){
var b64chars
= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var b64charcodes = function(){
var a = [];
var codeA = 'A'.charCodeAt(0);
var codea = 'a'.charCodeAt(0);
var code0 = '0'.charCodeAt(0);
for (var i = 0; i < 26; i ++) a.push(codeA + i);
for (var i = 0; i < 26; i ++) a.push(codea + i);
for (var i = 0; i < 10; i ++) a.push(code0 + i);
a.push('+'.charCodeAt(0));
a.push('/'.charCodeAt(0));
return a;
}();
var b64tab = function(bin){
var t = {};
for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i;
return t;
}(b64chars);
var stringToArray = function(s){
var a = [];
for (var i = 0, l = s.length; i < l; i ++) a[i] = s.charCodeAt(i);
return a;
};
var convertUTF8ArrayToBase64 = function(bin){
var padlen = 0;
while (bin.length % 3){
bin.push(0);
padlen++;
};
var b64 = [];
for (var i = 0, l = bin.length; i < l; i += 3){
var c0 = bin[i], c1 = bin[i+1], c2 = bin[i+2];
if (c0 >= 256 || c1 >= 256 || c2 >= 256)
throw 'unsupported character found';
var n = (c0 << 16) | (c1 << 8) | c2;
b64.push(
b64charcodes[ n >>> 18],
b64charcodes[(n >>> 12) & 63],
b64charcodes[(n >>> 6) & 63],
b64charcodes[ n & 63]
);
}
while (padlen--) b64[b64.length - padlen - 1] = '='.charCodeAt(0);
return chunkStringFromCharCodeApply(b64);
};
var convertBase64ToUTF8Array = function(b64){
b64 = b64.replace(/[^A-Za-z0-9+\/]+/g, '');
var bin = [];
var padlen = b64.length % 4;
for (var i = 0, l = b64.length; i < l; i += 4){
var n = ((b64tab[b64.charAt(i )] || 0) << 18)
| ((b64tab[b64.charAt(i+1)] || 0) << 12)
| ((b64tab[b64.charAt(i+2)] || 0) << 6)
| ((b64tab[b64.charAt(i+3)] || 0));
bin.push(
( n >> 16 ),
( (n >> 8) & 0xff ),
( n & 0xff )
);
}
bin.length -= [0,0,2,1][padlen];
return bin;
};
var convertUTF16ArrayToUTF8Array = function(uni){
var bin = [];
for (var i = 0, l = uni.length; i < l; i++){
var n = uni[i];
if (n < 0x80)
bin.push(n);
else if (n < 0x800)
bin.push(
0xc0 | (n >>> 6),
0x80 | (n & 0x3f));
else
bin.push(
0xe0 | ((n >>> 12) & 0x0f),
0x80 | ((n >>> 6) & 0x3f),
0x80 | (n & 0x3f));
}
return bin;
};
var convertUTF8ArrayToUTF16Array = function(bin){
var uni = [];
for (var i = 0, l = bin.length; i < l; i++){
var c0 = bin[i];
if (c0 < 0x80){
uni.push(c0);
}else{
var c1 = bin[++i];
if (c0 < 0xe0){
uni.push(((c0 & 0x1f) << 6) | (c1 & 0x3f));
}else{
var c2 = bin[++i];
uni.push(
((c0 & 0x0f) << 12) | ((c1 & 0x3f) << 6) | (c2 & 0x3f)
);
}
}
}
return uni;
};
var convertUTF8StringToBase64 = function(bin){
return convertUTF8ArrayToBase64(stringToArray(bin));
};
var convertBase64ToUTF8String = function(b64){
return chunkStringFromCharCodeApply(convertBase64ToUTF8Array(b64));
};
var convertUTF8StringToUTF16Array = function(bin){
return convertUTF8ArrayToUTF16Array(stringToArray(bin));
};
var convertUTF8ArrayToUTF16String = function(bin){
return chunkStringFromCharCodeApply(convertUTF8ArrayToUTF16Array(bin));
};
var convertUTF8StringToUTF16String = function(bin){
return chunkStringFromCharCodeApply(
convertUTF8ArrayToUTF16Array(stringToArray(bin))
);
};
var convertUTF16StringToUTF8Array = function(uni){
return convertUTF16ArrayToUTF8Array(stringToArray(uni));
};
var convertUTF16ArrayToUTF8String = function(uni){
return chunkStringFromCharCodeApply(convertUTF16ArrayToUTF8Array(uni));
};
var convertUTF16StringToUTF8String = function(uni){
return chunkStringFromCharCodeApply(
convertUTF16ArrayToUTF8Array(stringToArray(uni))
);
};
/*
* String.fromCharCode.apply will only handle arrays as big as 65536,
* after that it'll return a truncated string with no warning.
*/
var chunkStringFromCharCodeApply = function(arr){
var strs = [], i;
for (i = 0; i < arr.length; i += 65536){
strs.push(String.fromCharCode.apply(String, arr.slice(i, i+65536)));
}
return strs.join('');
};
if (global.btoa){
var btoa = global.btoa;
var convertUTF16StringToBase64 = function (uni){
return btoa(convertUTF16StringToUTF8String(uni));
};
}
else {
var btoa = convertUTF8StringToBase64;
var convertUTF16StringToBase64 = function (uni){
return convertUTF8ArrayToBase64(convertUTF16StringToUTF8Array(uni));
};
}
if (global.atob){
var atob = global.atob;
var convertBase64ToUTF16String = function (b64){
return convertUTF8StringToUTF16String(atob(b64));
};
}
else {
var atob = convertBase64ToUTF8String;
var convertBase64ToUTF16String = function (b64){
return convertUTF8ArrayToUTF16String(convertBase64ToUTF8Array(b64));
};
}
global.Base64 = {
convertUTF8ArrayToBase64:convertUTF8ArrayToBase64,
convertByteArrayToBase64:convertUTF8ArrayToBase64,
convertBase64ToUTF8Array:convertBase64ToUTF8Array,
convertBase64ToByteArray:convertBase64ToUTF8Array,
convertUTF16ArrayToUTF8Array:convertUTF16ArrayToUTF8Array,
convertUTF16ArrayToByteArray:convertUTF16ArrayToUTF8Array,
convertUTF8ArrayToUTF16Array:convertUTF8ArrayToUTF16Array,
convertByteArrayToUTF16Array:convertUTF8ArrayToUTF16Array,
convertUTF8StringToBase64:convertUTF8StringToBase64,
convertBase64ToUTF8String:convertBase64ToUTF8String,
convertUTF8StringToUTF16Array:convertUTF8StringToUTF16Array,
convertUTF8ArrayToUTF16String:convertUTF8ArrayToUTF16String,
convertByteArrayToUTF16String:convertUTF8ArrayToUTF16String,
convertUTF8StringToUTF16String:convertUTF8StringToUTF16String,
convertUTF16StringToUTF8Array:convertUTF16StringToUTF8Array,
convertUTF16StringToByteArray:convertUTF16StringToUTF8Array,
convertUTF16ArrayToUTF8String:convertUTF16ArrayToUTF8String,
convertUTF16StringToUTF8String:convertUTF16StringToUTF8String,
convertUTF16StringToBase64:convertUTF16StringToBase64,
convertBase64ToUTF16String:convertBase64ToUTF16String,
fromBase64:convertBase64ToUTF8String,
toBase64:convertUTF8StringToBase64,
atob:atob,
btoa:btoa,
utob:convertUTF16StringToUTF8String,
btou:convertUTF8StringToUTF16String,
encode:convertUTF16StringToBase64,
encodeURI:function(u){
return convertUTF16StringToBase64(u).replace(/[+\/]/g, function(m0){
return m0 == '+' ? '-' : '_';
}).replace(/=+$/, '');
},
decode:function(a){
return convertBase64ToUTF16String(a.replace(/[-_]/g, function(m0){
return m0 == '-' ? '+' : '/';
}));
}
};
})(this);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,114 @@
/*
Monokai style - ported by Luigi Maselli - http://grigio.org
*/
pre code {
display: block; padding: 0.5em;
background: #272822;
}
pre .tag,
pre .tag .title,
pre .keyword,
pre .literal,
pre .change,
pre .winutils,
pre .flow,
pre .lisp .title,
pre .clojure .built_in,
pre .nginx .title,
pre .tex .special {
color: #F92672;
}
pre code {
color: #DDD;
}
pre code .constant {
color: #66D9EF;
}
pre .class .title {
color: white;
}
pre .attribute,
pre .symbol,
pre .symbol .string,
pre .value,
pre .regexp {
color: #BF79DB;
}
pre .tag .value,
pre .string,
pre .subst,
pre .title,
pre .haskell .type,
pre .preprocessor,
pre .ruby .class .parent,
pre .built_in,
pre .sql .aggregate,
pre .django .template_tag,
pre .django .variable,
pre .smalltalk .class,
pre .javadoc,
pre .django .filter .argument,
pre .smalltalk .localvars,
pre .smalltalk .array,
pre .attr_selector,
pre .pseudo,
pre .addition,
pre .stream,
pre .envvar,
pre .apache .tag,
pre .apache .cbracket,
pre .tex .command,
pre .prompt {
color: #A6E22E;
}
pre .comment,
pre .java .annotation,
pre .python .decorator,
pre .template_comment,
pre .pi,
pre .doctype,
pre .deletion,
pre .shebang,
pre .apache .sqbracket,
pre .tex .formula {
color: #75715E;
}
pre .keyword,
pre .literal,
pre .css .id,
pre .phpdoc,
pre .title,
pre .haskell .type,
pre .vbscript .built_in,
pre .sql .aggregate,
pre .rsl .built_in,
pre .smalltalk .class,
pre .diff .header,
pre .chunk,
pre .winutils,
pre .bash .variable,
pre .apache .tag,
pre .tex .special,
pre .request,
pre .status {
font-weight: bold;
}
pre .coffeescript .javascript,
pre .javascript .xml,
pre .tex .formula,
pre .xml .javascript,
pre .xml .vbscript,
pre .xml .css,
pre .xml .cdata {
opacity: 0.5;
}

5
tools/nobin/js/jquery.js vendored Executable file

File diff suppressed because one or more lines are too long

1671
tools/nobin/js/rawdeflate.js Executable file

File diff suppressed because it is too large Load Diff

753
tools/nobin/js/rawinflate.js Executable file
View File

@@ -0,0 +1,753 @@
/*
* $Id: rawinflate.js,v 0.2 2009/03/01 18:32:24 dankogai Exp $
*
* original:
* http://www.onicos.com/staff/iz/amuse/javascript/expert/inflate.txt
*/
(function(){
/* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
* Version: 1.0.0.1
* LastModified: Dec 25 1999
*/
/* Interface:
* data = zip_inflate(src);
*/
/* constant parameters */
var zip_WSIZE = 32768; // Sliding Window size
var zip_STORED_BLOCK = 0;
var zip_STATIC_TREES = 1;
var zip_DYN_TREES = 2;
/* for inflate */
var zip_lbits = 9; // bits in base literal/length lookup table
var zip_dbits = 6; // bits in base distance lookup table
var zip_INBUFSIZ = 32768; // Input buffer size
var zip_INBUF_EXTRA = 64; // Extra buffer
/* variables (inflate) */
var zip_slide;
var zip_wp; // current position in slide
var zip_fixed_tl = null; // inflate static
var zip_fixed_td; // inflate static
var zip_fixed_bl, fixed_bd; // inflate static
var zip_bit_buf; // bit buffer
var zip_bit_len; // bits in bit buffer
var zip_method;
var zip_eof;
var zip_copy_leng;
var zip_copy_dist;
var zip_tl, zip_td; // literal/length and distance decoder tables
var zip_bl, zip_bd; // number of bits decoded by tl and td
var zip_inflate_data;
var zip_inflate_pos;
/* constant tables (inflate) */
var zip_MASK_BITS = new Array(
0x0000,
0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff);
// Tables for deflate from PKZIP's appnote.txt.
var zip_cplens = new Array( // Copy lengths for literal codes 257..285
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0);
/* note: see note #13 above about the 258 in this list. */
var zip_cplext = new Array( // Extra bits for literal codes 257..285
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99); // 99==invalid
var zip_cpdist = new Array( // Copy offsets for distance codes 0..29
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577);
var zip_cpdext = new Array( // Extra bits for distance codes
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13);
var zip_border = new Array( // Order of the bit length code lengths
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15);
/* objects (inflate) */
var zip_HuftList = function() {
this.next = null;
this.list = null;
}
var zip_HuftNode = function() {
this.e = 0; // number of extra bits or operation
this.b = 0; // number of bits in this code or subcode
// union
this.n = 0; // literal, length base, or distance base
this.t = null; // (zip_HuftNode) pointer to next level of table
}
var zip_HuftBuild = function(b, // code lengths in bits (all assumed <= BMAX)
n, // number of codes (assumed <= N_MAX)
s, // number of simple-valued codes (0..s-1)
d, // list of base values for non-simple codes
e, // list of extra bits for non-simple codes
mm // maximum lookup bits
) {
this.BMAX = 16; // maximum bit length of any code
this.N_MAX = 288; // maximum number of codes in any set
this.status = 0; // 0: success, 1: incomplete table, 2: bad input
this.root = null; // (zip_HuftList) starting table
this.m = 0; // maximum lookup bits, returns actual
/* Given a list of code lengths and a maximum table size, make a set of
tables to decode that set of codes. Return zero on success, one if
the given code set is incomplete (the tables are still built in this
case), two if the input is invalid (all zero length codes or an
oversubscribed set of lengths), and three if not enough memory.
The code with value 256 is special, and the tables are constructed
so that no bits beyond that code are fetched when that code is
decoded. */
{
var a; // counter for codes of length k
var c = new Array(this.BMAX+1); // bit length count table
var el; // length of EOB code (value 256)
var f; // i repeats in table every f entries
var g; // maximum code length
var h; // table level
var i; // counter, current code
var j; // counter
var k; // number of bits in current code
var lx = new Array(this.BMAX+1); // stack of bits per table
var p; // pointer into c[], b[], or v[]
var pidx; // index of p
var q; // (zip_HuftNode) points to current table
var r = new zip_HuftNode(); // table entry for structure assignment
var u = new Array(this.BMAX); // zip_HuftNode[BMAX][] table stack
var v = new Array(this.N_MAX); // values in order of bit length
var w;
var x = new Array(this.BMAX+1);// bit offsets, then code stack
var xp; // pointer into x or c
var y; // number of dummy codes added
var z; // number of entries in current table
var o;
var tail; // (zip_HuftList)
tail = this.root = null;
for(i = 0; i < c.length; i++)
c[i] = 0;
for(i = 0; i < lx.length; i++)
lx[i] = 0;
for(i = 0; i < u.length; i++)
u[i] = null;
for(i = 0; i < v.length; i++)
v[i] = 0;
for(i = 0; i < x.length; i++)
x[i] = 0;
// Generate counts for each bit length
el = n > 256 ? b[256] : this.BMAX; // set length of EOB code, if any
p = b; pidx = 0;
i = n;
do {
c[p[pidx]]++; // assume all entries <= BMAX
pidx++;
} while(--i > 0);
if(c[0] == n) { // null input--all zero length codes
this.root = null;
this.m = 0;
this.status = 0;
return;
}
// Find minimum and maximum length, bound *m by those
for(j = 1; j <= this.BMAX; j++)
if(c[j] != 0)
break;
k = j; // minimum code length
if(mm < j)
mm = j;
for(i = this.BMAX; i != 0; i--)
if(c[i] != 0)
break;
g = i; // maximum code length
if(mm > i)
mm = i;
// Adjust last length count to fill out codes, if needed
for(y = 1 << j; j < i; j++, y <<= 1)
if((y -= c[j]) < 0) {
this.status = 2; // bad input: more codes than bits
this.m = mm;
return;
}
if((y -= c[i]) < 0) {
this.status = 2;
this.m = mm;
return;
}
c[i] += y;
// Generate starting offsets into the value table for each length
x[1] = j = 0;
p = c;
pidx = 1;
xp = 2;
while(--i > 0) // note that i == g from above
x[xp++] = (j += p[pidx++]);
// Make a table of values in order of bit lengths
p = b; pidx = 0;
i = 0;
do {
if((j = p[pidx++]) != 0)
v[x[j]++] = i;
} while(++i < n);
n = x[g]; // set n to length of v
// Generate the Huffman codes and for each, make the table entries
x[0] = i = 0; // first Huffman code is zero
p = v; pidx = 0; // grab values in bit order
h = -1; // no tables yet--level -1
w = lx[0] = 0; // no bits decoded yet
q = null; // ditto
z = 0; // ditto
// go through the bit lengths (k already is bits in shortest code)
for(; k <= g; k++) {
a = c[k];
while(a-- > 0) {
// here i is the Huffman code of length k bits for value p[pidx]
// make tables up to required level
while(k > w + lx[1 + h]) {
w += lx[1 + h]; // add bits already decoded
h++;
// compute minimum size table less than or equal to *m bits
z = (z = g - w) > mm ? mm : z; // upper limit
if((f = 1 << (j = k - w)) > a + 1) { // try a k-w bit table
// too few codes for k-w bit table
f -= a + 1; // deduct codes from patterns left
xp = k;
while(++j < z) { // try smaller tables up to z bits
if((f <<= 1) <= c[++xp])
break; // enough codes to use up j bits
f -= c[xp]; // else deduct codes from patterns
}
}
if(w + j > el && w < el)
j = el - w; // make EOB code end at table
z = 1 << j; // table entries for j-bit table
lx[1 + h] = j; // set table size in stack
// allocate and link in new table
q = new Array(z);
for(o = 0; o < z; o++) {
q[o] = new zip_HuftNode();
}
if(tail == null)
tail = this.root = new zip_HuftList();
else
tail = tail.next = new zip_HuftList();
tail.next = null;
tail.list = q;
u[h] = q; // table starts after link
/* connect to last table, if there is one */
if(h > 0) {
x[h] = i; // save pattern for backing up
r.b = lx[h]; // bits to dump before this table
r.e = 16 + j; // bits in this table
r.t = q; // pointer to this table
j = (i & ((1 << w) - 1)) >> (w - lx[h]);
u[h-1][j].e = r.e;
u[h-1][j].b = r.b;
u[h-1][j].n = r.n;
u[h-1][j].t = r.t;
}
}
// set up table entry in r
r.b = k - w;
if(pidx >= n)
r.e = 99; // out of values--invalid code
else if(p[pidx] < s) {
r.e = (p[pidx] < 256 ? 16 : 15); // 256 is end-of-block code
r.n = p[pidx++]; // simple code is just the value
} else {
r.e = e[p[pidx] - s]; // non-simple--look up in lists
r.n = d[p[pidx++] - s];
}
// fill code-like entries with r //
f = 1 << (k - w);
for(j = i >> w; j < z; j += f) {
q[j].e = r.e;
q[j].b = r.b;
q[j].n = r.n;
q[j].t = r.t;
}
// backwards increment the k-bit code i
for(j = 1 << (k - 1); (i & j) != 0; j >>= 1)
i ^= j;
i ^= j;
// backup over finished tables
while((i & ((1 << w) - 1)) != x[h]) {
w -= lx[h]; // don't need to update q
h--;
}
}
}
/* return actual size of base table */
this.m = lx[1];
/* Return true (1) if we were given an incomplete table */
this.status = ((y != 0 && g != 1) ? 1 : 0);
} /* end of constructor */
}
/* routines (inflate) */
var zip_GET_BYTE = function() {
if(zip_inflate_data.length == zip_inflate_pos)
return -1;
return zip_inflate_data.charCodeAt(zip_inflate_pos++) & 0xff;
}
var zip_NEEDBITS = function(n) {
while(zip_bit_len < n) {
zip_bit_buf |= zip_GET_BYTE() << zip_bit_len;
zip_bit_len += 8;
}
}
var zip_GETBITS = function(n) {
return zip_bit_buf & zip_MASK_BITS[n];
}
var zip_DUMPBITS = function(n) {
zip_bit_buf >>= n;
zip_bit_len -= n;
}
var zip_inflate_codes = function(buff, off, size) {
/* inflate (decompress) the codes in a deflated (compressed) block.
Return an error code or zero if it all goes ok. */
var e; // table entry flag/number of extra bits
var t; // (zip_HuftNode) pointer to table entry
var n;
if(size == 0)
return 0;
// inflate the coded data
n = 0;
for(;;) { // do until end of block
zip_NEEDBITS(zip_bl);
t = zip_tl.list[zip_GETBITS(zip_bl)];
e = t.e;
while(e > 16) {
if(e == 99)
return -1;
zip_DUMPBITS(t.b);
e -= 16;
zip_NEEDBITS(e);
t = t.t[zip_GETBITS(e)];
e = t.e;
}
zip_DUMPBITS(t.b);
if(e == 16) { // then it's a literal
zip_wp &= zip_WSIZE - 1;
buff[off + n++] = zip_slide[zip_wp++] = t.n;
if(n == size)
return size;
continue;
}
// exit if end of block
if(e == 15)
break;
// it's an EOB or a length
// get length of block to copy
zip_NEEDBITS(e);
zip_copy_leng = t.n + zip_GETBITS(e);
zip_DUMPBITS(e);
// decode distance of block to copy
zip_NEEDBITS(zip_bd);
t = zip_td.list[zip_GETBITS(zip_bd)];
e = t.e;
while(e > 16) {
if(e == 99)
return -1;
zip_DUMPBITS(t.b);
e -= 16;
zip_NEEDBITS(e);
t = t.t[zip_GETBITS(e)];
e = t.e;
}
zip_DUMPBITS(t.b);
zip_NEEDBITS(e);
zip_copy_dist = zip_wp - t.n - zip_GETBITS(e);
zip_DUMPBITS(e);
// do the copy
while(zip_copy_leng > 0 && n < size) {
zip_copy_leng--;
zip_copy_dist &= zip_WSIZE - 1;
zip_wp &= zip_WSIZE - 1;
buff[off + n++] = zip_slide[zip_wp++]
= zip_slide[zip_copy_dist++];
}
if(n == size)
return size;
}
zip_method = -1; // done
return n;
}
var zip_inflate_stored = function(buff, off, size) {
/* "decompress" an inflated type 0 (stored) block. */
var n;
// go to byte boundary
n = zip_bit_len & 7;
zip_DUMPBITS(n);
// get the length and its complement
zip_NEEDBITS(16);
n = zip_GETBITS(16);
zip_DUMPBITS(16);
zip_NEEDBITS(16);
if(n != ((~zip_bit_buf) & 0xffff))
return -1; // error in compressed data
zip_DUMPBITS(16);
// read and output the compressed data
zip_copy_leng = n;
n = 0;
while(zip_copy_leng > 0 && n < size) {
zip_copy_leng--;
zip_wp &= zip_WSIZE - 1;
zip_NEEDBITS(8);
buff[off + n++] = zip_slide[zip_wp++] =
zip_GETBITS(8);
zip_DUMPBITS(8);
}
if(zip_copy_leng == 0)
zip_method = -1; // done
return n;
}
var zip_inflate_fixed = function(buff, off, size) {
/* decompress an inflated type 1 (fixed Huffman codes) block. We should
either replace this with a custom decoder, or at least precompute the
Huffman tables. */
// if first time, set up tables for fixed blocks
if(zip_fixed_tl == null) {
var i; // temporary variable
var l = new Array(288); // length list for huft_build
var h; // zip_HuftBuild
// literal table
for(i = 0; i < 144; i++)
l[i] = 8;
for(; i < 256; i++)
l[i] = 9;
for(; i < 280; i++)
l[i] = 7;
for(; i < 288; i++) // make a complete, but wrong code set
l[i] = 8;
zip_fixed_bl = 7;
h = new zip_HuftBuild(l, 288, 257, zip_cplens, zip_cplext,
zip_fixed_bl);
if(h.status != 0) {
alert("HufBuild error: "+h.status);
return -1;
}
zip_fixed_tl = h.root;
zip_fixed_bl = h.m;
// distance table
for(i = 0; i < 30; i++) // make an incomplete code set
l[i] = 5;
zip_fixed_bd = 5;
h = new zip_HuftBuild(l, 30, 0, zip_cpdist, zip_cpdext, zip_fixed_bd);
if(h.status > 1) {
zip_fixed_tl = null;
alert("HufBuild error: "+h.status);
return -1;
}
zip_fixed_td = h.root;
zip_fixed_bd = h.m;
}
zip_tl = zip_fixed_tl;
zip_td = zip_fixed_td;
zip_bl = zip_fixed_bl;
zip_bd = zip_fixed_bd;
return zip_inflate_codes(buff, off, size);
}
var zip_inflate_dynamic = function(buff, off, size) {
// decompress an inflated type 2 (dynamic Huffman codes) block.
var i; // temporary variables
var j;
var l; // last length
var n; // number of lengths to get
var t; // (zip_HuftNode) literal/length code table
var nb; // number of bit length codes
var nl; // number of literal/length codes
var nd; // number of distance codes
var ll = new Array(286+30); // literal/length and distance code lengths
var h; // (zip_HuftBuild)
for(i = 0; i < ll.length; i++)
ll[i] = 0;
// read in table lengths
zip_NEEDBITS(5);
nl = 257 + zip_GETBITS(5); // number of literal/length codes
zip_DUMPBITS(5);
zip_NEEDBITS(5);
nd = 1 + zip_GETBITS(5); // number of distance codes
zip_DUMPBITS(5);
zip_NEEDBITS(4);
nb = 4 + zip_GETBITS(4); // number of bit length codes
zip_DUMPBITS(4);
if(nl > 286 || nd > 30)
return -1; // bad lengths
// read in bit-length-code lengths
for(j = 0; j < nb; j++)
{
zip_NEEDBITS(3);
ll[zip_border[j]] = zip_GETBITS(3);
zip_DUMPBITS(3);
}
for(; j < 19; j++)
ll[zip_border[j]] = 0;
// build decoding table for trees--single level, 7 bit lookup
zip_bl = 7;
h = new zip_HuftBuild(ll, 19, 19, null, null, zip_bl);
if(h.status != 0)
return -1; // incomplete code set
zip_tl = h.root;
zip_bl = h.m;
// read in literal and distance code lengths
n = nl + nd;
i = l = 0;
while(i < n) {
zip_NEEDBITS(zip_bl);
t = zip_tl.list[zip_GETBITS(zip_bl)];
j = t.b;
zip_DUMPBITS(j);
j = t.n;
if(j < 16) // length of code in bits (0..15)
ll[i++] = l = j; // save last length in l
else if(j == 16) { // repeat last length 3 to 6 times
zip_NEEDBITS(2);
j = 3 + zip_GETBITS(2);
zip_DUMPBITS(2);
if(i + j > n)
return -1;
while(j-- > 0)
ll[i++] = l;
} else if(j == 17) { // 3 to 10 zero length codes
zip_NEEDBITS(3);
j = 3 + zip_GETBITS(3);
zip_DUMPBITS(3);
if(i + j > n)
return -1;
while(j-- > 0)
ll[i++] = 0;
l = 0;
} else { // j == 18: 11 to 138 zero length codes
zip_NEEDBITS(7);
j = 11 + zip_GETBITS(7);
zip_DUMPBITS(7);
if(i + j > n)
return -1;
while(j-- > 0)
ll[i++] = 0;
l = 0;
}
}
// build the decoding tables for literal/length and distance codes
zip_bl = zip_lbits;
h = new zip_HuftBuild(ll, nl, 257, zip_cplens, zip_cplext, zip_bl);
if(zip_bl == 0) // no literals or lengths
h.status = 1;
if(h.status != 0) {
if(h.status == 1)
;// **incomplete literal tree**
return -1; // incomplete code set
}
zip_tl = h.root;
zip_bl = h.m;
for(i = 0; i < nd; i++)
ll[i] = ll[i + nl];
zip_bd = zip_dbits;
h = new zip_HuftBuild(ll, nd, 0, zip_cpdist, zip_cpdext, zip_bd);
zip_td = h.root;
zip_bd = h.m;
if(zip_bd == 0 && nl > 257) { // lengths but no distances
// **incomplete distance tree**
return -1;
}
if(h.status == 1) {
;// **incomplete distance tree**
}
if(h.status != 0)
return -1;
// decompress until an end-of-block code
return zip_inflate_codes(buff, off, size);
}
var zip_inflate_start = function() {
var i;
if(zip_slide == null)
zip_slide = new Array(2 * zip_WSIZE);
zip_wp = 0;
zip_bit_buf = 0;
zip_bit_len = 0;
zip_method = -1;
zip_eof = false;
zip_copy_leng = zip_copy_dist = 0;
zip_tl = null;
}
var zip_inflate_internal = function(buff, off, size) {
// decompress an inflated entry
var n, i;
n = 0;
while(n < size) {
if(zip_eof && zip_method == -1)
return n;
if(zip_copy_leng > 0) {
if(zip_method != zip_STORED_BLOCK) {
// STATIC_TREES or DYN_TREES
while(zip_copy_leng > 0 && n < size) {
zip_copy_leng--;
zip_copy_dist &= zip_WSIZE - 1;
zip_wp &= zip_WSIZE - 1;
buff[off + n++] = zip_slide[zip_wp++] =
zip_slide[zip_copy_dist++];
}
} else {
while(zip_copy_leng > 0 && n < size) {
zip_copy_leng--;
zip_wp &= zip_WSIZE - 1;
zip_NEEDBITS(8);
buff[off + n++] = zip_slide[zip_wp++] = zip_GETBITS(8);
zip_DUMPBITS(8);
}
if(zip_copy_leng == 0)
zip_method = -1; // done
}
if(n == size)
return n;
}
if(zip_method == -1) {
if(zip_eof)
break;
// read in last block bit
zip_NEEDBITS(1);
if(zip_GETBITS(1) != 0)
zip_eof = true;
zip_DUMPBITS(1);
// read in block type
zip_NEEDBITS(2);
zip_method = zip_GETBITS(2);
zip_DUMPBITS(2);
zip_tl = null;
zip_copy_leng = 0;
}
switch(zip_method) {
case 0: // zip_STORED_BLOCK
i = zip_inflate_stored(buff, off + n, size - n);
break;
case 1: // zip_STATIC_TREES
if(zip_tl != null)
i = zip_inflate_codes(buff, off + n, size - n);
else
i = zip_inflate_fixed(buff, off + n, size - n);
break;
case 2: // zip_DYN_TREES
if(zip_tl != null)
i = zip_inflate_codes(buff, off + n, size - n);
else
i = zip_inflate_dynamic(buff, off + n, size - n);
break;
default: // error
i = -1;
break;
}
if(i == -1) {
if(zip_eof)
return 0;
return -1;
}
n += i;
}
return n;
}
var zip_inflate = function(str) {
var i, j;
zip_inflate_start();
zip_inflate_data = str;
zip_inflate_pos = 0;
var buff = new Array(1024);
var aout = [];
while((i = zip_inflate_internal(buff, 0, buff.length)) > 0) {
var cbuf = new Array(i);
for(j = 0; j < i; j++){
cbuf[j] = String.fromCharCode(buff[j]);
}
aout[aout.length] = cbuf.join("");
}
zip_inflate_data = null; // G.C.
return aout.join("");
}
if (! window.RawDeflate) RawDeflate = {};
RawDeflate.inflate = zip_inflate;
})();

45
tools/nobin/js/sjcl.js Executable file
View File

@@ -0,0 +1,45 @@
"use strict";var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a},notReady:function(a){this.toString=function(){return"NOT READY: "+this.message};this.message=a}}};
if(typeof module!="undefined"&&module.exports)module.exports=sjcl;
sjcl.cipher.aes=function(a){this.i[0][0][0]||this.B();var b,c,d,e,f=this.i[0][4],g=this.i[1];b=a.length;var h=1;if(b!==4&&b!==6&&b!==8)throw new sjcl.exception.invalid("invalid aes key size");this.a=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(a%b===0||b===8&&a%b===4){c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255];if(a%b===0){c=c<<8^c>>>24^h<<24;h=h<<1^(h>>7)*283}}d[a]=d[a-b]^c}for(b=0;a;b++,a--){c=d[b&3?a:a-4];e[b]=a<=4||b<4?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^
g[3][f[c&255]]}};
sjcl.cipher.aes.prototype={encrypt:function(a){return this.K(a,0)},decrypt:function(a){return this.K(a,1)},i:[[[],[],[],[],[]],[[],[],[],[],[]]],B:function(){var a=this.i[0],b=this.i[1],c=a[4],d=b[4],e,f,g,h=[],i=[],j,k,l,m;for(e=0;e<0x100;e++)i[(h[e]=e<<1^(e>>7)*283)^e]=e;for(f=g=0;!c[f];f^=j||1,g=i[g]||1){l=g^g<<1^g<<2^g<<3^g<<4;l=l>>8^l&255^99;c[f]=l;d[l]=f;k=h[e=h[j=h[f]]];m=k*0x1010101^e*0x10001^j*0x101^f*0x1010100;k=h[l]*0x101^l*0x1010100;for(e=0;e<4;e++){a[e][f]=k=k<<24^k>>>8;b[e][l]=m=m<<24^m>>>8}}for(e=
0;e<5;e++){a[e]=a[e].slice(0);b[e]=b[e].slice(0)}},K:function(a,b){if(a.length!==4)throw new sjcl.exception.invalid("invalid aes block size");var c=this.a[b],d=a[0]^c[0],e=a[b?3:1]^c[1],f=a[2]^c[2];a=a[b?1:3]^c[3];var g,h,i,j=c.length/4-2,k,l=4,m=[0,0,0,0];g=this.i[b];var n=g[0],o=g[1],p=g[2],q=g[3],r=g[4];for(k=0;k<j;k++){g=n[d>>>24]^o[e>>16&255]^p[f>>8&255]^q[a&255]^c[l];h=n[e>>>24]^o[f>>16&255]^p[a>>8&255]^q[d&255]^c[l+1];i=n[f>>>24]^o[a>>16&255]^p[d>>8&255]^q[e&255]^c[l+2];a=n[a>>>24]^o[d>>16&
255]^p[e>>8&255]^q[f&255]^c[l+3];l+=4;d=g;e=h;f=i}for(k=0;k<4;k++){m[b?3&-k:k]=r[d>>>24]<<24^r[e>>16&255]<<16^r[f>>8&255]<<8^r[a&255]^c[l++];g=d;d=e;e=f;f=a;a=g}return m}};
sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.Q(a.slice(b/32),32-(b&31)).slice(1);return c===undefined?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<<c)-1},concat:function(a,b){if(a.length===0||b.length===0)return a.concat(b);var c=a[a.length-1],d=sjcl.bitArray.getPartial(c);return d===32?a.concat(b):sjcl.bitArray.Q(b,d,c|0,a.slice(0,a.length-1))},bitLength:function(a){var b=a.length;
if(b===0)return 0;return(b-1)*32+sjcl.bitArray.getPartial(a[b-1])},clamp:function(a,b){if(a.length*32<b)return a;a=a.slice(0,Math.ceil(b/32));var c=a.length;b&=31;if(c>0&&b)a[c-1]=sjcl.bitArray.partial(b,a[c-1]&2147483648>>b-1,1);return a},partial:function(a,b,c){if(a===32)return b;return(c?b|0:b<<32-a)+a*0x10000000000},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return false;var c=0,d;for(d=0;d<a.length;d++)c|=
a[d]^b[d];return c===0},Q:function(a,b,c,d){var e;e=0;if(d===undefined)d=[];for(;b>=32;b-=32){d.push(c);c=0}if(b===0)return d.concat(a);for(e=0;e<a.length;e++){d.push(c|a[e]>>>b);c=a[e]<<32-b}e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,b+a>32?c:d.pop(),1));return d},j:function(a,b){return[a[0]^b[0],a[1]^b[1],a[2]^b[2],a[3]^b[3]]}};
sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d<c/8;d++){if((d&3)===0)e=a[d/4];b+=String.fromCharCode(e>>>24);e<<=8}return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c<a.length;c++){d=d<<8|a.charCodeAt(c);if((c&3)===3){b.push(d);d=0}}c&3&&b.push(sjcl.bitArray.partial(8*(c&3),d));return b}};
sjcl.codec.hex={fromBits:function(a){var b="",c;for(c=0;c<a.length;c++)b+=((a[c]|0)+0xf00000000000).toString(16).substr(4);return b.substr(0,sjcl.bitArray.bitLength(a)/4)},toBits:function(a){var b,c=[],d;a=a.replace(/\s|0x/g,"");d=a.length;a+="00000000";for(b=0;b<a.length;b+=8)c.push(parseInt(a.substr(b,8),16)^0);return sjcl.bitArray.clamp(c,d*4)}};
sjcl.codec.base64={H:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fromBits:function(a,b,c){var d="",e=0,f=sjcl.codec.base64.H,g=0,h=sjcl.bitArray.bitLength(a);if(c)f=f.substr(0,62)+"-_";for(c=0;d.length*6<h;){d+=f.charAt((g^a[c]>>>e)>>>26);if(e<6){g=a[c]<<6-e;e+=26;c++}else{g<<=6;e-=6}}for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d=0,e=sjcl.codec.base64.H,f=0,g;if(b)e=e.substr(0,62)+"-_";for(b=0;b<a.length;b++){g=e.indexOf(a.charAt(b));
if(g<0)throw new sjcl.exception.invalid("this isn't base64!");if(d>26){d-=26;c.push(f^g>>>d);f=g<<32-d}else{d+=6;f^=g<<32-d}}d&56&&c.push(sjcl.bitArray.partial(d&56,f,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.a[0]||this.B();if(a){this.p=a.p.slice(0);this.k=a.k.slice(0);this.f=a.f}else this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};
sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.p=this.O.slice(0);this.k=[];this.f=0;return this},update:function(a){if(typeof a==="string")a=sjcl.codec.utf8String.toBits(a);var b,c=this.k=sjcl.bitArray.concat(this.k,a);b=this.f;a=this.f=b+sjcl.bitArray.bitLength(a);for(b=512+b&-512;b<=a;b+=512)this.G(c.splice(0,16));return this},finalize:function(){var a,b=this.k,c=this.p;b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.f/
4294967296));for(b.push(this.f|0);b.length;)this.G(b.splice(0,16));this.reset();return c},O:[],a:[],B:function(){function a(e){return(e-Math.floor(e))*0x100000000|0}var b=0,c=2,d;a:for(;b<64;c++){for(d=2;d*d<=c;d++)if(c%d===0)continue a;if(b<8)this.O[b]=a(Math.pow(c,0.5));this.a[b]=a(Math.pow(c,1/3));b++}},G:function(a){var b,c,d=a.slice(0),e=this.p,f=this.a,g=e[0],h=e[1],i=e[2],j=e[3],k=e[4],l=e[5],m=e[6],n=e[7];for(a=0;a<64;a++){if(a<16)b=d[a];else{b=d[a+1&15];c=d[a+14&15];b=d[a&15]=(b>>>7^b>>>18^
b>>>3^b<<25^b<<14)+(c>>>17^c>>>19^c>>>10^c<<15^c<<13)+d[a&15]+d[a+9&15]|0}b=b+n+(k>>>6^k>>>11^k>>>25^k<<26^k<<21^k<<7)+(m^k&(l^m))+f[a];n=m;m=l;l=k;k=j+b|0;j=i;i=h;h=g;g=b+(h&i^j&(h^i))+(h>>>2^h>>>13^h>>>22^h<<30^h<<19^h<<10)|0}e[0]=e[0]+g|0;e[1]=e[1]+h|0;e[2]=e[2]+i|0;e[3]=e[3]+j|0;e[4]=e[4]+k|0;e[5]=e[5]+l|0;e[6]=e[6]+m|0;e[7]=e[7]+n|0}};
sjcl.mode.ccm={name:"ccm",encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,i=h.bitLength(c)/8,j=h.bitLength(g)/8;e=e||64;d=d||[];if(i<7)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;f<4&&j>>>8*f;f++);if(f<15-i)f=15-i;c=h.clamp(c,8*(15-f));b=sjcl.mode.ccm.J(a,b,c,d,e,f);g=sjcl.mode.ccm.l(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),i=f.clamp(b,h-e),j=f.bitSlice(b,
h-e);h=(h-e)/8;if(g<7)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;b<4&&h>>>8*b;b++);if(b<15-g)b=15-g;c=f.clamp(c,8*(15-b));i=sjcl.mode.ccm.l(a,i,c,j,e,b);a=sjcl.mode.ccm.J(a,i.data,c,d,e,b);if(!f.equal(i.tag,a))throw new sjcl.exception.corrupt("ccm: tag doesn't match");return i.data},J:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,i=h.j;e/=8;if(e%2||e<4||e>16)throw new sjcl.exception.invalid("ccm: invalid tag length");if(d.length>0xffffffff||b.length>0xffffffff)throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data");
f=[h.partial(8,(d.length?64:0)|e-2<<2|f-1)];f=h.concat(f,c);f[3]|=h.bitLength(b)/8;f=a.encrypt(f);if(d.length){c=h.bitLength(d)/8;if(c<=65279)g=[h.partial(16,c)];else if(c<=0xffffffff)g=h.concat([h.partial(16,65534)],[c]);g=h.concat(g,d);for(d=0;d<g.length;d+=4)f=a.encrypt(i(f,g.slice(d,d+4).concat([0,0,0])))}for(d=0;d<b.length;d+=4)f=a.encrypt(i(f,b.slice(d,d+4).concat([0,0,0])));return h.clamp(f,e*8)},l:function(a,b,c,d,e,f){var g,h=sjcl.bitArray;g=h.j;var i=b.length,j=h.bitLength(b);c=h.concat([h.partial(8,
f-1)],c).concat([0,0,0]).slice(0,4);d=h.bitSlice(g(d,a.encrypt(c)),0,e);if(!i)return{tag:d,data:[]};for(g=0;g<i;g+=4){c[3]++;e=a.encrypt(c);b[g]^=e[0];b[g+1]^=e[1];b[g+2]^=e[2];b[g+3]^=e[3]}return{tag:d,data:h.clamp(b,j)}}};
sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){if(sjcl.bitArray.bitLength(c)!==128)throw new sjcl.exception.invalid("ocb iv must be 128 bits");var g,h=sjcl.mode.ocb2.D,i=sjcl.bitArray,j=i.j,k=[0,0,0,0];c=h(a.encrypt(c));var l,m=[];d=d||[];e=e||64;for(g=0;g+4<b.length;g+=4){l=b.slice(g,g+4);k=j(k,l);m=m.concat(j(c,a.encrypt(j(c,l))));c=h(c)}l=b.slice(g);b=i.bitLength(l);g=a.encrypt(j(c,[0,0,0,b]));l=i.clamp(j(l.concat([0,0,0]),g),b);k=j(k,j(l.concat([0,0,0]),g));k=a.encrypt(j(k,j(c,h(c))));
if(d.length)k=j(k,f?d:sjcl.mode.ocb2.pmac(a,d));return m.concat(i.concat(l,i.clamp(k,e)))},decrypt:function(a,b,c,d,e,f){if(sjcl.bitArray.bitLength(c)!==128)throw new sjcl.exception.invalid("ocb iv must be 128 bits");e=e||64;var g=sjcl.mode.ocb2.D,h=sjcl.bitArray,i=h.j,j=[0,0,0,0],k=g(a.encrypt(c)),l,m,n=sjcl.bitArray.bitLength(b)-e,o=[];d=d||[];for(c=0;c+4<n/32;c+=4){l=i(k,a.decrypt(i(k,b.slice(c,c+4))));j=i(j,l);o=o.concat(l);k=g(k)}m=n-c*32;l=a.encrypt(i(k,[0,0,0,m]));l=i(l,h.clamp(b.slice(c),
m).concat([0,0,0]));j=i(j,l);j=a.encrypt(i(j,i(k,g(k))));if(d.length)j=i(j,f?d:sjcl.mode.ocb2.pmac(a,d));if(!h.equal(h.clamp(j,e),h.bitSlice(b,n)))throw new sjcl.exception.corrupt("ocb: tag doesn't match");return o.concat(h.clamp(l,m))},pmac:function(a,b){var c,d=sjcl.mode.ocb2.D,e=sjcl.bitArray,f=e.j,g=[0,0,0,0],h=a.encrypt([0,0,0,0]);h=f(h,d(d(h)));for(c=0;c+4<b.length;c+=4){h=d(h);g=f(g,a.encrypt(f(h,b.slice(c,c+4))))}b=b.slice(c);if(e.bitLength(b)<128){h=f(h,d(h));b=e.concat(b,[2147483648|0,0,
0,0])}g=f(g,b);return a.encrypt(f(d(f(h,d(h))),g))},D:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^(a[0]>>>31)*135]}};
sjcl.mode.gcm={name:"gcm",encrypt:function(a,b,c,d,e){var f=b.slice(0);b=sjcl.bitArray;e=e||128;d=d||[];a=sjcl.mode.gcm.l(true,a,f,d,c,e);return b.concat(a.data,a.tag)},decrypt:function(a,b,c,d,e){var f=b.slice(0),g=sjcl.bitArray,h=g.bitLength(f);e=e||128;d=d||[];if(e<=h){b=g.bitSlice(f,h-e);f=g.bitSlice(f,0,h-e)}else{b=f;f=[]}a=sjcl.mode.gcm.l(false,a,f,d,c,e);if(!g.equal(a.tag,b))throw new sjcl.exception.corrupt("gcm: tag doesn't match");return a.data},T:function(a,b){var c,d,e,f,g=sjcl.bitArray.j;
d=[0,0,0,0];e=b.slice(0);for(b=0;b<128;b++){if(c=(a[Math.floor(b/32)]&1<<31-b%32)!==0)d=g(d,e);f=(e[3]&1)!==0;for(c=3;c>0;c--)e[c]=e[c]>>>1|(e[c-1]&1)<<31;e[0]>>>=1;if(f)e[0]^=-0x1f000000}return d},e:function(a,b,c){var d,e=c.length;b=b.slice(0);for(d=0;d<e;d+=4){b[0]^=0xffffffff&c[d];b[1]^=0xffffffff&c[d+1];b[2]^=0xffffffff&c[d+2];b[3]^=0xffffffff&c[d+3];b=sjcl.mode.gcm.T(b,a)}return b},l:function(a,b,c,d,e,f){var g,h,i,j,k,l,m,n,o=sjcl.bitArray;l=c.length;m=o.bitLength(c);n=o.bitLength(d);h=o.bitLength(e);
g=b.encrypt([0,0,0,0]);if(h===96){e=e.slice(0);e=o.concat(e,[1])}else{e=sjcl.mode.gcm.e(g,[0,0,0,0],e);e=sjcl.mode.gcm.e(g,e,[0,0,Math.floor(h/0x100000000),h&0xffffffff])}h=sjcl.mode.gcm.e(g,[0,0,0,0],d);k=e.slice(0);d=h.slice(0);a||(d=sjcl.mode.gcm.e(g,h,c));for(j=0;j<l;j+=4){k[3]++;i=b.encrypt(k);c[j]^=i[0];c[j+1]^=i[1];c[j+2]^=i[2];c[j+3]^=i[3]}c=o.clamp(c,m);if(a)d=sjcl.mode.gcm.e(g,h,c);a=[Math.floor(n/0x100000000),n&0xffffffff,Math.floor(m/0x100000000),m&0xffffffff];d=sjcl.mode.gcm.e(g,d,a);i=
b.encrypt(e);d[0]^=i[0];d[1]^=i[1];d[2]^=i[2];d[3]^=i[3];return{tag:o.bitSlice(d,0,f),data:c}}};sjcl.misc.hmac=function(a,b){this.N=b=b||sjcl.hash.sha256;var c=[[],[]],d=b.prototype.blockSize/32;this.n=[new b,new b];if(a.length>d)a=b.hash(a);for(b=0;b<d;b++){c[0][b]=a[b]^909522486;c[1][b]=a[b]^1549556828}this.n[0].update(c[0]);this.n[1].update(c[1])};sjcl.misc.hmac.prototype.encrypt=sjcl.misc.hmac.prototype.mac=function(a){a=(new this.N(this.n[0])).update(a).finalize();return(new this.N(this.n[1])).update(a).finalize()};
sjcl.misc.pbkdf2=function(a,b,c,d,e){c=c||1E3;if(d<0||c<0)throw sjcl.exception.invalid("invalid params to pbkdf2");if(typeof a==="string")a=sjcl.codec.utf8String.toBits(a);e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,i,j=[],k=sjcl.bitArray;for(i=1;32*j.length<(d||1);i++){e=f=a.encrypt(k.concat(b,[i]));for(g=1;g<c;g++){f=a.encrypt(f);for(h=0;h<f.length;h++)e[h]^=f[h]}j=j.concat(e)}if(d)j=k.clamp(j,d);return j};
sjcl.random={randomWords:function(a,b){var c=[];b=this.isReady(b);var d;if(b===0)throw new sjcl.exception.notReady("generator isn't seeded");else b&2&&this.W(!(b&1));for(b=0;b<a;b+=4){(b+1)%0x10000===0&&this.M();d=this.A();c.push(d[0],d[1],d[2],d[3])}this.M();return c.slice(0,a)},setDefaultParanoia:function(a){this.w=a},addEntropy:function(a,b,c){c=c||"user";var d,e,f=(new Date).valueOf(),g=this.s[c],h=this.isReady(),i=0;d=this.I[c];if(d===undefined)d=this.I[c]=this.S++;if(g===undefined)g=this.s[c]=
0;this.s[c]=(this.s[c]+1)%this.b.length;switch(typeof a){case "number":if(b===undefined)b=1;this.b[g].update([d,this.z++,1,b,f,1,a|0]);break;case "object":c=Object.prototype.toString.call(a);if(c==="[object Uint32Array]"){e=[];for(c=0;c<a.length;c++)e.push(a[c]);a=e}else{if(c!=="[object Array]")i=1;for(c=0;c<a.length&&!i;c++)if(typeof a[c]!="number")i=1}if(!i){if(b===undefined)for(c=b=0;c<a.length;c++)for(e=a[c];e>0;){b++;e>>>=1}this.b[g].update([d,this.z++,2,b,f,a.length].concat(a))}break;case "string":if(b===
undefined)b=a.length;this.b[g].update([d,this.z++,3,b,f,a.length]);this.b[g].update(a);break;default:i=1}if(i)throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");this.m[g]+=b;this.g+=b;if(h===0){this.isReady()!==0&&this.L("seeded",Math.max(this.h,this.g));this.L("progress",this.getProgress())}},isReady:function(a){a=this.F[a!==undefined?a:this.w];return this.h&&this.h>=a?this.m[0]>80&&(new Date).valueOf()>this.P?3:1:this.g>=a?2:0},getProgress:function(a){a=
this.F[a?a:this.w];return this.h>=a?1:this.g>a?1:this.g/a},startCollectors:function(){if(!this.o){if(window.addEventListener){window.addEventListener("load",this.q,false);window.addEventListener("mousemove",this.r,false)}else if(document.attachEvent){document.attachEvent("onload",this.q);document.attachEvent("onmousemove",this.r)}else throw new sjcl.exception.bug("can't attach event");this.o=true}},stopCollectors:function(){if(this.o){if(window.removeEventListener){window.removeEventListener("load",
this.q,false);window.removeEventListener("mousemove",this.r,false)}else if(window.detachEvent){window.detachEvent("onload",this.q);window.detachEvent("onmousemove",this.r)}this.o=false}},addEventListener:function(a,b){this.t[a][this.R++]=b},removeEventListener:function(a,b){var c;a=this.t[a];var d=[];for(c in a)a.hasOwnProperty(c)&&a[c]===b&&d.push(c);for(b=0;b<d.length;b++){c=d[b];delete a[c]}},b:[new sjcl.hash.sha256],m:[0],C:0,s:{},z:0,I:{},S:0,h:0,g:0,P:0,a:[0,0,0,0,0,0,0,0],d:[0,0,0,0],u:undefined,
w:6,o:false,t:{progress:{},seeded:{}},R:0,F:[0,48,64,96,128,192,0x100,384,512,768,1024],A:function(){for(var a=0;a<4;a++){this.d[a]=this.d[a]+1|0;if(this.d[a])break}return this.u.encrypt(this.d)},M:function(){this.a=this.A().concat(this.A());this.u=new sjcl.cipher.aes(this.a)},V:function(a){this.a=sjcl.hash.sha256.hash(this.a.concat(a));this.u=new sjcl.cipher.aes(this.a);for(a=0;a<4;a++){this.d[a]=this.d[a]+1|0;if(this.d[a])break}},W:function(a){var b=[],c=0,d;this.P=b[0]=(new Date).valueOf()+3E4;for(d=
0;d<16;d++)b.push(Math.random()*0x100000000|0);for(d=0;d<this.b.length;d++){b=b.concat(this.b[d].finalize());c+=this.m[d];this.m[d]=0;if(!a&&this.C&1<<d)break}if(this.C>=1<<this.b.length){this.b.push(new sjcl.hash.sha256);this.m.push(0)}this.g-=c;if(c>this.h)this.h=c;this.C++;this.V(b)},r:function(a){sjcl.random.addEntropy([a.x||a.clientX||a.offsetX||0,a.y||a.clientY||a.offsetY||0],2,"mouse")},q:function(){sjcl.random.addEntropy((new Date).valueOf(),2,"loadtime")},L:function(a,b){var c;a=sjcl.random.t[a];
var d=[];for(c in a)a.hasOwnProperty(c)&&d.push(a[c]);for(c=0;c<d.length;c++)d[c](b)}};try{var s=new Uint32Array(32);crypto.getRandomValues(s);sjcl.random.addEntropy(s,1024,"crypto['getRandomValues']")}catch(t){}
sjcl.json={defaults:{v:1,iter:1E3,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},encrypt:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.c({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.c(f,c);c=f.adata;if(typeof f.salt==="string")f.salt=sjcl.codec.base64.toBits(f.salt);if(typeof f.iv==="string")f.iv=sjcl.codec.base64.toBits(f.iv);if(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||typeof a==="string"&&f.iter<=100||f.ts!==64&&f.ts!==96&&f.ts!==128||f.ks!==128&&f.ks!==192&&f.ks!==0x100||f.iv.length<
2||f.iv.length>4)throw new sjcl.exception.invalid("json encrypt: invalid parameters");if(typeof a==="string"){g=sjcl.misc.cachedPbkdf2(a,f);a=g.key.slice(0,f.ks/32);f.salt=g.salt}if(typeof b==="string")b=sjcl.codec.utf8String.toBits(b);if(typeof c==="string")c=sjcl.codec.utf8String.toBits(c);g=new sjcl.cipher[f.cipher](a);e.c(d,f);d.key=a;f.ct=sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return e.encode(f)},decrypt:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.c(e.c(e.c({},e.defaults),e.decode(b)),
c,true);var f;c=b.adata;if(typeof b.salt==="string")b.salt=sjcl.codec.base64.toBits(b.salt);if(typeof b.iv==="string")b.iv=sjcl.codec.base64.toBits(b.iv);if(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||typeof a==="string"&&b.iter<=100||b.ts!==64&&b.ts!==96&&b.ts!==128||b.ks!==128&&b.ks!==192&&b.ks!==0x100||!b.iv||b.iv.length<2||b.iv.length>4)throw new sjcl.exception.invalid("json decrypt: invalid parameters");if(typeof a==="string"){f=sjcl.misc.cachedPbkdf2(a,b);a=f.key.slice(0,b.ks/32);b.salt=f.salt}if(typeof c===
"string")c=sjcl.codec.utf8String.toBits(c);f=new sjcl.cipher[b.cipher](a);c=sjcl.mode[b.mode].decrypt(f,b.ct,b.iv,c,b.ts);e.c(d,b);d.key=a;return sjcl.codec.utf8String.fromBits(c)},encode:function(a){var b,c="{",d="";for(b in a)if(a.hasOwnProperty(b)){if(!b.match(/^[a-z0-9]+$/i))throw new sjcl.exception.invalid("json encode: invalid property name");c+=d+'"'+b+'":';d=",";switch(typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';break;case "object":c+='"'+
sjcl.codec.base64.fromBits(a[b],0)+'"';break;default:throw new sjcl.exception.bug("json encode: unsupported type");}}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");if(!a.match(/^\{.*\}$/))throw new sjcl.exception.invalid("json decode: this isn't json!");a=a.replace(/^\{|\}$/g,"").split(/,/);var b={},c,d;for(c=0;c<a.length;c++){if(!(d=a[c].match(/^(?:(["']?)([a-z][a-z0-9]*)\1):(?:(\d+)|"([a-z0-9+\/%*_.@=\-]*)")$/i)))throw new sjcl.exception.invalid("json decode: this isn't json!");b[d[2]]=
d[3]?parseInt(d[3],10):d[2].match(/^(ct|salt|iv)$/)?sjcl.codec.base64.toBits(d[4]):unescape(d[4])}return b},c:function(a,b,c){if(a===undefined)a={};if(b===undefined)return a;var d;for(d in b)if(b.hasOwnProperty(d)){if(c&&a[d]!==undefined&&a[d]!==b[d])throw new sjcl.exception.invalid("required parameter overridden");a[d]=b[d]}return a},Y:function(a,b){var c={},d;for(d in a)if(a.hasOwnProperty(d)&&a[d]!==b[d])c[d]=a[d];return c},X:function(a,b){var c={},d;for(d=0;d<b.length;d++)if(a[b[d]]!==undefined)c[b[d]]=
a[b[d]];return c}};sjcl.encrypt=sjcl.json.encrypt;sjcl.decrypt=sjcl.json.decrypt;sjcl.misc.U={};sjcl.misc.cachedPbkdf2=function(a,b){var c=sjcl.misc.U,d;b=b||{};d=b.iter||1E3;c=c[a]=c[a]||{};d=c[d]=c[d]||{firstSalt:b.salt&&b.salt.length?b.salt.slice(0):sjcl.random.randomWords(2,0)};c=b.salt===undefined?d.firstSalt:b.salt;d[c]=d[c]||sjcl.misc.pbkdf2(a,c,b.iter);return{key:d[c].slice(0),salt:c.slice(0)}};

608
tools/nobin/js/zerobin-fr.js Executable file
View File

@@ -0,0 +1,608 @@
/**
* ZeroBin 0.19
*
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @author sebsauvage
*/
// Immediately start random number generator collector.
sjcl.random.startCollectors();
/**
* Converts a duration (in seconds) into human readable format.
*
* @param int seconds
* @return string
*/
function secondsToHuman(seconds)
{
if (seconds<60) { var v=Math.floor(seconds); return v+' seconde'+((v>1)?'s':''); }
if (seconds<60*60) { var v=Math.floor(seconds/60); return v+' minute'+((v>1)?'s':''); }
if (seconds<60*60*24) { var v=Math.floor(seconds/(60*60)); return v+' heure'+((v>1)?'s':''); }
// If less than 2 months, display in days:
if (seconds<60*60*24*60) { var v=Math.floor(seconds/(60*60*24)); return v+' jour'+((v>1)?'s':''); }
var v=Math.floor(seconds/(60*60*24*30)); return v+' mois';
}
/**
* Converts an associative array to an encoded string
* for appending to the anchor.
*
* @param object associative_array Object to be serialized
* @return string
*/
function hashToParameterString(associativeArray)
{
var parameterString = ""
for (key in associativeArray)
{
if( parameterString === "" )
{
parameterString = encodeURIComponent(key);
parameterString += "=" + encodeURIComponent(associativeArray[key]);
} else {
parameterString += "&" + encodeURIComponent(key);
parameterString += "=" + encodeURIComponent(associativeArray[key]);
}
}
//padding for URL shorteners
parameterString += "&p=p";
return parameterString;
}
/**
* Converts a string to an associative array.
*
* @param string parameter_string String containing parameters
* @return object
*/
function parameterStringToHash(parameterString)
{
var parameterHash = {};
var parameterArray = parameterString.split("&");
for (var i = 0; i < parameterArray.length; i++) {
//var currentParamterString = decodeURIComponent(parameterArray[i]);
var pair = parameterArray[i].split("=");
var key = decodeURIComponent(pair[0]);
var value = decodeURIComponent(pair[1]);
parameterHash[key] = value;
}
return parameterHash;
}
/**
* Get an associative array of the parameters found in the anchor
*
* @return object
**/
function getParameterHash()
{
var hashIndex = window.location.href.indexOf("#");
if (hashIndex >= 0) {
return parameterStringToHash(window.location.href.substring(hashIndex + 1));
} else {
return {};
}
}
/**
* Compress a message (deflate compression). Returns base64 encoded data.
*
* @param string message
* @return base64 string data
*/
function compress(message) {
return Base64.toBase64( RawDeflate.deflate( Base64.utob(message) ) );
}
/**
* Decompress a message compressed with compress().
*/
function decompress(data) {
return Base64.btou( RawDeflate.inflate( Base64.fromBase64(data) ) );
}
/**
* Compress, then encrypt message with key.
*
* @param string key
* @param string message
* @return encrypted string data
*/
function zeroCipher(key, message) {
return sjcl.encrypt(key,compress(message));
}
/**
* Decrypt message with key, then decompress.
*
* @param key
* @param encrypted string data
* @return string readable message
*/
function zeroDecipher(key, data) {
return decompress(sjcl.decrypt(key,data));
}
/**
* @return the current script location (without search or hash part of the URL).
* eg. http://server.com/zero/?aaaa#bbbb --> http://server.com/zero/
*/
function scriptLocation() {
var scriptLocation = window.location.href.substring(0,window.location.href.length
- window.location.search.length - window.location.hash.length);
var hashIndex = scriptLocation.indexOf("#");
if (hashIndex !== -1) {
scriptLocation = scriptLocation.substring(0, hashIndex)
}
return scriptLocation
}
/**
* @return the paste unique identifier from the URL
* eg. 'c05354954c49a487'
*/
function pasteID() {
return window.location.search.substring(1);
}
function htmlEntities(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
/**
* Set text of a DOM element (required for IE)
* This is equivalent to element.text(text)
* @param object element : a DOM element.
* @param string text : the text to enter.
*/
function setElementText(element, text) {
// For IE<10.
if ($('div#oldienotice').is(":visible")) {
// IE<10 does not support white-space:pre-wrap; so we have to do this BIG UGLY STINKING THING.
var html = htmlEntities(text).replace(/\n/ig,"\r\n<br>");
element.html('<pre>'+html+'</pre>');
}
// for other (sane) browsers:
else {
element.text(text);
}
}
/** Apply syntax coloring to clear text area.
*/
function applySyntaxColoring()
{
if ($('div#cleartext').html().substring(0,11) != '<pre><code>')
{
// highlight.js expects code to be surrounded by <pre><code>
$('div#cleartext').html('<pre><code>'+ $('div#cleartext').html()+'</code></pre>');
}
hljs.highlightBlock(document.getElementById('cleartext'));
$('div#cleartext').css('padding','0'); // Remove white padding around code box.
}
/**
* Show decrypted text in the display area, including discussion (if open)
*
* @param string key : decryption key
* @param array comments : Array of messages to display (items = array with keys ('data','meta')
*/
function displayMessages(key, comments) {
try { // Try to decrypt the paste.
var cleartext = zeroDecipher(key, comments[0].data);
} catch(err) {
$('div#cleartext').hide();
$('button#clonebutton').hide();
showError('Impossible de déchiffrer les données (mauvaise clé ?)');
return;
}
setElementText($('div#cleartext'), cleartext);
urls2links($('div#cleartext')); // Convert URLs to clickable links.
// comments[0] is the paste itself.
if (comments[0].meta.syntaxcoloring) applySyntaxColoring();
// Display paste expiration.
if (comments[0].meta.expire_date) $('div#remainingtime').removeClass('foryoureyesonly').text('Ce document expirera dans '+secondsToHuman(comments[0].meta.remaining_time)+'.').show();
if (comments[0].meta.burnafterreading) {
$('div#remainingtime').addClass('foryoureyesonly').text('POUR VOS YEUX UNIQUEMENT : Ne fermez pas cette fenêtre, ce message ne pourra pas être affiché à nouveau.').show();
$('button#clonebutton').hide(); // Discourage cloning (as it can't really be prevented).
}
// If the discussion is opened on this paste, display it.
if (comments[0].meta.opendiscussion) {
$('div#comments').html('');
// For each comment.
for (var i = 1; i < comments.length; i++) {
var comment=comments[i];
var cleartext="[Impossible de déchiffrer le commentaire ; mauvaise clé ?]";
try {
cleartext = zeroDecipher(key, comment.data);
} catch(err) { }
var place = $('div#comments');
// If parent comment exists, display below (CSS will automatically shift it right.)
var cname = 'div#comment_'+comment.meta.parentid
// If the element exists in page
if ($(cname).length) {
place = $(cname);
}
var divComment = $('<div class="comment" id="comment_' + comment.meta.commentid+'">'
+ '<div class="commentmeta"><span class="nickname"></span><span class="commentdate"></span></div><div class="commentdata"></div>'
+ '<button onclick="open_reply($(this),\'' + comment.meta.commentid + '\');return false;">Répondre</button>'
+ '</div>');
setElementText(divComment.find('div.commentdata'), cleartext);
// Convert URLs to clickable links in comment.
urls2links(divComment.find('div.commentdata'));
divComment.find('span.nickname').html('<i>(Anonyme)</i>');
// Try to get optional nickname:
try {
divComment.find('span.nickname').text(zeroDecipher(key, comment.meta.nickname));
} catch(err) { }
divComment.find('span.commentdate').text(' ('+(new Date(comment.meta.postdate*1000).toString())+')').attr('title','CommentID: ' + comment.meta.commentid);
// If an avatar is available, display it.
if (comment.meta.vizhash) {
divComment.find('span.nickname').before('<img src="' + comment.meta.vizhash + '" class="vizhash" title="Avatar anonyme (Vizhash de ladresse IP)" />');
}
place.append(divComment);
}
$('div#comments').append('<div class="comment"><button onclick="open_reply($(this),\'' + pasteID() + '\');return false;">Ajouter un comentaire</button></div>');
$('div#discussion').show();
}
}
/**
* Open the comment entry when clicking the "Reply" button of a comment.
* @param object source : element which emitted the event.
* @param string commentid = identifier of the comment we want to reply to.
*/
function open_reply(source, commentid) {
$('div.reply').remove(); // Remove any other reply area.
source.after('<div class="reply">'
+ '<input type="text" id="nickname" title="Pseudo facultatif…" value="Pseudo facultatif…" />'
+ '<textarea id="replymessage" class="replymessage" cols="80" rows="7"></textarea>'
+ '<br><button id="replybutton" onclick="send_comment(\'' + commentid + '\');return false;">Publier le commentaire</button>'
+ '<div id="replystatus">&nbsp;</div>'
+ '</div>');
$('input#nickname').focus(function() {
$(this).css('color', '#000');
if ($(this).val() == $(this).attr('title')) {
$(this).val('');
}
});
$('textarea#replymessage').focus();
}
/**
* Send a reply in a discussion.
* @param string parentid : the comment identifier we want to send a reply to.
*/
function send_comment(parentid) {
// Do not send if no data.
if ($('textarea#replymessage').val().length==0) {
return;
}
showStatus('Envoi du commentaire…', spin=true);
var cipherdata = zeroCipher(pageKey(), $('textarea#replymessage').val());
var ciphernickname = '';
var nick=$('input#nickname').val();
if (nick != '' && nick != 'Pseudo facultatif…') {
ciphernickname = zeroCipher(pageKey(), nick);
}
var data_to_send = { data:cipherdata,
parentid: parentid,
pasteid: pasteID(),
nickname: ciphernickname
};
$.post(scriptLocation(), data_to_send, 'json')
.error(function() {
showError('Le commentaire na pas pu être envoyé (erreur du serveur ou qui ne répond pas).');
})
.success(function(data) {
if (data.status == 0) {
showStatus('Commentaire publié.');
location.reload();
}
else if (data.status==1) {
showError('Impossible de publier le commentaire : '+data.message);
}
else {
showError('Impossible de publier le commentaire.');
}
});
}
/**
* Send a new paste to server
*/
function send_data() {
// Do not send if no data.
if ($('textarea#message').val().length == 0) {
return;
}
// If sjcl has not collected enough entropy yet, display a message.
if (!sjcl.random.isReady())
{
showStatus('Envoi du texte… (Déplacez votre souris pour ajouter de lentropie)…', spin=true);
sjcl.random.addEventListener('seeded', function(){ send_data(); });
return;
}
showStatus('Envoi du texte…', spin=true);
var randomkey = sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0);
var cipherdata = zeroCipher(randomkey, $('textarea#message').val());
var data_to_send = { data: cipherdata,
expire: $('select#pasteExpiration').val(),
burnafterreading: $('input#burnafterreading').is(':checked') ? 1 : 0,
opendiscussion: $('input#opendiscussion').is(':checked') ? 1 : 0,
syntaxcoloring: $('input#syntaxcoloring').is(':checked') ? 1 : 0
};
$.post(scriptLocation(), data_to_send, 'json')
.error(function() {
showError('Les données nont pas pu être envoyées (erreur du serveur ou qui ne répond pas).');
})
.success(function(data) {
if (data.status == 0) {
stateExistingPaste();
var url = scriptLocation() + "?" + data.id + '#' + randomkey;
var deleteUrl = scriptLocation() + "?pasteid=" + data.id + '&deletetoken=' + data.deletetoken;
showStatus('');
$('div#pastelink').html('Votre texte se trouve à cette adresse : <br /> <span class="tag success"><a id="pasteurl" href="' + url + '">' + url + '</a></span><br /> <span id="copyhint">(Tapez CTRL+C pour copier le lien)</span>');
$('div#deletelink').html('Lien de suppression : <span class="tag alert">' + deleteUrl + "</span>");
$('div#pasteresult').show();
selectText('pasteurl'); // We pre-select the link so that the user only has to CTRL+C the link.
setElementText($('div#cleartext'), $('textarea#message').val());
urls2links($('div#cleartext'));
// FIXME: Add option to remove syntax highlighting ?
if ($('input#syntaxcoloring').is(':checked')) applySyntaxColoring();
showStatus('');
}
else if (data.status==1) {
showError('Impossible denregistrer le texte : '+data.message);
}
else {
showError('Impossible denregistrer le texte.');
}
});
}
/** Text range selection.
* From: http://stackoverflow.com/questions/985272/jquery-selecting-text-in-an-element-akin-to-highlighting-with-your-mouse
* @param string element : Indentifier of the element to select (id="").
*/
function selectText(element) {
var doc = document
, text = doc.getElementById(element)
, range, selection
;
if (doc.body.createTextRange) { //ms
range = doc.body.createTextRange();
range.moveToElementText(text);
range.select();
} else if (window.getSelection) { //all others
selection = window.getSelection();
range = doc.createRange();
range.selectNodeContents(text);
selection.removeAllRanges();
selection.addRange(range);
}
}
/**
* Put the screen in "New paste" mode.
*/
function stateNewPaste() {
$('button#sendbutton').show();
$('button#clonebutton').hide();
$('button#rawtextbutton').hide();
$('div#expiration').show();
$('div#remainingtime').hide();
$('div#burnafterreadingoption').show();
$('div#opendisc').show();
$('div#syntaxcoloringoption').show();
$('button#newbutton').show();
$('div#pasteresult').hide();
$('textarea#message').text('');
$('textarea#message').show();
$('div#cleartext').hide();
$('div#message').focus();
$('div#discussion').hide();
}
/**
* Put the screen in "Existing paste" mode.
*/
function stateExistingPaste() {
$('button#sendbutton').hide();
// No "clone" for IE<10.
if ($('div#oldienotice').is(":visible")) {
$('button#clonebutton').hide();
}
else {
$('button#clonebutton').show();
}
$('button#rawtextbutton').show();
$('div#expiration').hide();
$('div#burnafterreadingoption').hide();
$('div#opendisc').hide();
$('div#syntaxcoloringoption').hide();
$('button#newbutton').show();
$('div#pasteresult').hide();
$('textarea#message').hide();
$('div#cleartext').show();
}
/** Return raw text
*/
function rawText()
{
var paste = $('div#cleartext').html();
var newDoc = document.open('text/html', 'replace');
newDoc.write('<pre>'+paste+'</pre>');
newDoc.close();
}
/**
* Clone the current paste.
*/
function clonePaste() {
stateNewPaste();
//Erase the id and the key in url
history.replaceState(document.title, document.title, scriptLocation());
showStatus('');
$('textarea#message').text($('div#cleartext').text());
}
/**
* Create a new paste.
*/
function newPaste() {
stateNewPaste();
showStatus('');
$('textarea#message').text('');
}
/**
* Display an error message
* (We use the same function for paste and reply to comments)
*/
function showError(message) {
$('div#status').addClass('errorMessage').text(message);
$('div#replystatus').addClass('errorMessage').text(message);
}
/**
* Display status
* (We use the same function for paste and reply to comments)
*
* @param string message : text to display
* @param boolean spin (optional) : tell if the "spinning" animation should be displayed.
*/
function showStatus(message, spin) {
$('div#replystatus').removeClass('errorMessage');
$('div#replystatus').text(message);
if (!message) {
$('div#status').html('&nbsp;');
return;
}
if (message == '') {
$('div#status').html('&nbsp;');
return;
}
$('div#status').removeClass('errorMessage');
$('div#status').text(message);
if (spin) {
var img = '<img src="img/busy.gif" style="width:16px;height:9px;margin:0px 4px 0px 0px;" />';
$('div#status').prepend(img);
$('div#replystatus').prepend(img);
}
}
/**
* Convert URLs to clickable links.
* URLs to handle:
* <code>
* magnet:?xt.1=urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C&xt.2=urn:sha1:TXGCZQTH26NL6OUQAJJPFALHG2LTGBC7
* http://localhost:8800/zero/?6f09182b8ea51997#WtLEUO5Epj9UHAV9JFs+6pUQZp13TuspAUjnF+iM+dM=
* http://user:password@localhost:8800/zero/?6f09182b8ea51997#WtLEUO5Epj9UHAV9JFs+6pUQZp13TuspAUjnF+iM+dM=
* </code>
*
* @param object element : a jQuery DOM element.
* @FIXME: add ppa & apt links.
*/
function urls2links(element) {
var re = /((http|https|ftp):\/\/[\w?=&.\/-;#@~%+-]+(?![\w\s?&.\/;#~%"=-]*>))/ig;
element.html(element.html().replace(re,'<a href="$1" rel="nofollow">$1</a>'));
var re = /((magnet):[\w?=&.\/-;#@~%+-]+)/ig;
element.html(element.html().replace(re,'<a href="$1">$1</a>'));
}
/**
* Return the deciphering key stored in anchor part of the URL
*/
function pageKey() {
var key = window.location.hash.substring(1); // Get key
// Some stupid web 2.0 services and redirectors add data AFTER the anchor
// (such as &utm_source=...).
// We will strip any additional data.
// First, strip everything after the equal sign (=) which signals end of base64 string.
i = key.indexOf('='); if (i>-1) { key = key.substring(0,i+1); }
// If the equal sign was not present, some parameters may remain:
i = key.indexOf('&'); if (i>-1) { key = key.substring(0,i); }
// Then add trailing equal sign if it's missing
if (key.charAt(key.length-1)!=='=') key+='=';
return key;
}
$(function() {
// If "burn after reading" is checked, disable discussion.
$('input#burnafterreading').change(function() {
if ($(this).is(':checked') ) {
$('div#opendisc').addClass('buttondisabled');
$('input#opendiscussion').attr({checked: false});
$('input#opendiscussion').attr('disabled',true);
}
else {
$('div#opendisc').removeClass('buttondisabled');
$('input#opendiscussion').removeAttr('disabled');
}
});
// Display status returned by php code if any (eg. Paste was properly deleted.)
if ($('div#status').text().length > 0) {
showStatus($('div#status').text(),false);
return;
}
$('div#status').html('&nbsp;'); // Keep line height even if content empty.
// Display an existing paste
if ($('div#cipherdata').text().length > 1) {
// Missing decryption key in URL ?
if (window.location.hash.length == 0) {
showError('Impossible de déchiffrer le texte : il manque la clé de chiffrement dans lURL (Avez-vous utilisé une redirection ou un raccourcisseur dURL qui aurait tronqué une partie de lURL ?)');
return;
}
// List of messages to display
var messages = jQuery.parseJSON($('div#cipherdata').text());
// Show proper elements on screen.
stateExistingPaste();
displayMessages(pageKey(), messages);
}
// Display error message from php code.
else if ($('div#errormessage').text().length>1) {
showError($('div#errormessage').text());
}
// Create a new paste.
else {
newPaste();
}
});

608
tools/nobin/js/zerobin.js Executable file
View File

@@ -0,0 +1,608 @@
/**
* ZeroBin 0.19
*
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @author sebsauvage
*/
// Immediately start random number generator collector.
sjcl.random.startCollectors();
/**
* Converts a duration (in seconds) into human readable format.
*
* @param int seconds
* @return string
*/
function secondsToHuman(seconds)
{
if (seconds<60) { var v=Math.floor(seconds); return v+' second'+((v>1)?'s':''); }
if (seconds<60*60) { var v=Math.floor(seconds/60); return v+' minute'+((v>1)?'s':''); }
if (seconds<60*60*24) { var v=Math.floor(seconds/(60*60)); return v+' hour'+((v>1)?'s':''); }
// If less than 2 months, display in days:
if (seconds<60*60*24*60) { var v=Math.floor(seconds/(60*60*24)); return v+' day'+((v>1)?'s':''); }
var v=Math.floor(seconds/(60*60*24*30)); return v+' month'+((v>1)?'s':'');
}
/**
* Converts an associative array to an encoded string
* for appending to the anchor.
*
* @param object associative_array Object to be serialized
* @return string
*/
function hashToParameterString(associativeArray)
{
var parameterString = ""
for (key in associativeArray)
{
if( parameterString === "" )
{
parameterString = encodeURIComponent(key);
parameterString += "=" + encodeURIComponent(associativeArray[key]);
} else {
parameterString += "&" + encodeURIComponent(key);
parameterString += "=" + encodeURIComponent(associativeArray[key]);
}
}
//padding for URL shorteners
parameterString += "&p=p";
return parameterString;
}
/**
* Converts a string to an associative array.
*
* @param string parameter_string String containing parameters
* @return object
*/
function parameterStringToHash(parameterString)
{
var parameterHash = {};
var parameterArray = parameterString.split("&");
for (var i = 0; i < parameterArray.length; i++) {
//var currentParamterString = decodeURIComponent(parameterArray[i]);
var pair = parameterArray[i].split("=");
var key = decodeURIComponent(pair[0]);
var value = decodeURIComponent(pair[1]);
parameterHash[key] = value;
}
return parameterHash;
}
/**
* Get an associative array of the parameters found in the anchor
*
* @return object
**/
function getParameterHash()
{
var hashIndex = window.location.href.indexOf("#");
if (hashIndex >= 0) {
return parameterStringToHash(window.location.href.substring(hashIndex + 1));
} else {
return {};
}
}
/**
* Compress a message (deflate compression). Returns base64 encoded data.
*
* @param string message
* @return base64 string data
*/
function compress(message) {
return Base64.toBase64( RawDeflate.deflate( Base64.utob(message) ) );
}
/**
* Decompress a message compressed with compress().
*/
function decompress(data) {
return Base64.btou( RawDeflate.inflate( Base64.fromBase64(data) ) );
}
/**
* Compress, then encrypt message with key.
*
* @param string key
* @param string message
* @return encrypted string data
*/
function zeroCipher(key, message) {
return sjcl.encrypt(key,compress(message));
}
/**
* Decrypt message with key, then decompress.
*
* @param key
* @param encrypted string data
* @return string readable message
*/
function zeroDecipher(key, data) {
return decompress(sjcl.decrypt(key,data));
}
/**
* @return the current script location (without search or hash part of the URL).
* eg. http://server.com/zero/?aaaa#bbbb --> http://server.com/zero/
*/
function scriptLocation() {
var scriptLocation = window.location.href.substring(0,window.location.href.length
- window.location.search.length - window.location.hash.length);
var hashIndex = scriptLocation.indexOf("#");
if (hashIndex !== -1) {
scriptLocation = scriptLocation.substring(0, hashIndex)
}
return scriptLocation
}
/**
* @return the paste unique identifier from the URL
* eg. 'c05354954c49a487'
*/
function pasteID() {
return window.location.search.substring(1);
}
function htmlEntities(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
/**
* Set text of a DOM element (required for IE)
* This is equivalent to element.text(text)
* @param object element : a DOM element.
* @param string text : the text to enter.
*/
function setElementText(element, text) {
// For IE<10.
if ($('div#oldienotice').is(":visible")) {
// IE<10 does not support white-space:pre-wrap; so we have to do this BIG UGLY STINKING THING.
var html = htmlEntities(text).replace(/\n/ig,"\r\n<br>");
element.html('<pre>'+html+'</pre>');
}
// for other (sane) browsers:
else {
element.text(text);
}
}
/** Apply syntax coloring to clear text area.
*/
function applySyntaxColoring()
{
if ($('div#cleartext').html().substring(0,11) != '<pre><code>')
{
// highlight.js expects code to be surrounded by <pre><code>
$('div#cleartext').html('<pre><code>'+ $('div#cleartext').html()+'</code></pre>');
}
hljs.highlightBlock(document.getElementById('cleartext'));
$('div#cleartext').css('padding','0'); // Remove white padding around code box.
}
/**
* Show decrypted text in the display area, including discussion (if open)
*
* @param string key : decryption key
* @param array comments : Array of messages to display (items = array with keys ('data','meta')
*/
function displayMessages(key, comments) {
try { // Try to decrypt the paste.
var cleartext = zeroDecipher(key, comments[0].data);
} catch(err) {
$('div#cleartext').hide();
$('button#clonebutton').hide();
showError('Could not decrypt data (Wrong key ?)');
return;
}
setElementText($('div#cleartext'), cleartext);
urls2links($('div#cleartext')); // Convert URLs to clickable links.
// comments[0] is the paste itself.
if (comments[0].meta.syntaxcoloring) applySyntaxColoring();
// Display paste expiration.
if (comments[0].meta.expire_date) $('div#remainingtime').removeClass('foryoureyesonly').text('This document will expire in '+secondsToHuman(comments[0].meta.remaining_time)+'.').show();
if (comments[0].meta.burnafterreading) {
$('div#remainingtime').addClass('foryoureyesonly').text('FOR YOUR EYES ONLY. Don\'t close this window, this message can\'t be displayed again.').show();
$('button#clonebutton').hide(); // Discourage cloning (as it can't really be prevented).
}
// If the discussion is opened on this paste, display it.
if (comments[0].meta.opendiscussion) {
$('div#comments').html('');
// For each comment.
for (var i = 1; i < comments.length; i++) {
var comment=comments[i];
var cleartext="[Could not decrypt comment ; Wrong key ?]";
try {
cleartext = zeroDecipher(key, comment.data);
} catch(err) { }
var place = $('div#comments');
// If parent comment exists, display below (CSS will automatically shift it right.)
var cname = 'div#comment_'+comment.meta.parentid
// If the element exists in page
if ($(cname).length) {
place = $(cname);
}
var divComment = $('<div class="comment" id="comment_' + comment.meta.commentid+'">'
+ '<div class="commentmeta"><span class="nickname"></span><span class="commentdate"></span></div><div class="commentdata"></div>'
+ '<button onclick="open_reply($(this),\'' + comment.meta.commentid + '\');return false;">Reply</button>'
+ '</div>');
setElementText(divComment.find('div.commentdata'), cleartext);
// Convert URLs to clickable links in comment.
urls2links(divComment.find('div.commentdata'));
divComment.find('span.nickname').html('<i>(Anonymous)</i>');
// Try to get optional nickname:
try {
divComment.find('span.nickname').text(zeroDecipher(key, comment.meta.nickname));
} catch(err) { }
divComment.find('span.commentdate').text(' ('+(new Date(comment.meta.postdate*1000).toString())+')').attr('title','CommentID: ' + comment.meta.commentid);
// If an avatar is available, display it.
if (comment.meta.vizhash) {
divComment.find('span.nickname').before('<img src="' + comment.meta.vizhash + '" class="vizhash" title="Anonymous avatar (Vizhash of the IP address)" />');
}
place.append(divComment);
}
$('div#comments').append('<div class="comment"><button onclick="open_reply($(this),\'' + pasteID() + '\');return false;">Add comment</button></div>');
$('div#discussion').show();
}
}
/**
* Open the comment entry when clicking the "Reply" button of a comment.
* @param object source : element which emitted the event.
* @param string commentid = identifier of the comment we want to reply to.
*/
function open_reply(source, commentid) {
$('div.reply').remove(); // Remove any other reply area.
source.after('<div class="reply">'
+ '<input type="text" id="nickname" title="Optional nickname..." value="Optional nickname..." />'
+ '<textarea id="replymessage" class="replymessage" cols="80" rows="7"></textarea>'
+ '<br><button id="replybutton" onclick="send_comment(\'' + commentid + '\');return false;">Post comment</button>'
+ '<div id="replystatus">&nbsp;</div>'
+ '</div>');
$('input#nickname').focus(function() {
$(this).css('color', '#000');
if ($(this).val() == $(this).attr('title')) {
$(this).val('');
}
});
$('textarea#replymessage').focus();
}
/**
* Send a reply in a discussion.
* @param string parentid : the comment identifier we want to send a reply to.
*/
function send_comment(parentid) {
// Do not send if no data.
if ($('textarea#replymessage').val().length==0) {
return;
}
showStatus('Sending comment...', spin=true);
var cipherdata = zeroCipher(pageKey(), $('textarea#replymessage').val());
var ciphernickname = '';
var nick=$('input#nickname').val();
if (nick != '' && nick != 'Optional nickname...') {
ciphernickname = zeroCipher(pageKey(), nick);
}
var data_to_send = { data:cipherdata,
parentid: parentid,
pasteid: pasteID(),
nickname: ciphernickname
};
$.post(scriptLocation(), data_to_send, 'json')
.error(function() {
showError('Comment could not be sent (serveur error or not responding).');
})
.success(function(data) {
if (data.status == 0) {
showStatus('Comment posted.');
location.reload();
}
else if (data.status==1) {
showError('Could not post comment: '+data.message);
}
else {
showError('Could not post comment.');
}
});
}
/**
* Send a new paste to server
*/
function send_data() {
// Do not send if no data.
if ($('textarea#message').val().length == 0) {
return;
}
// If sjcl has not collected enough entropy yet, display a message.
if (!sjcl.random.isReady())
{
showStatus('Sending paste (Please move your mouse for more entropy)...', spin=true);
sjcl.random.addEventListener('seeded', function(){ send_data(); });
return;
}
showStatus('Sending paste...', spin=true);
var randomkey = sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0);
var cipherdata = zeroCipher(randomkey, $('textarea#message').val());
var data_to_send = { data: cipherdata,
expire: $('select#pasteExpiration').val(),
burnafterreading: $('input#burnafterreading').is(':checked') ? 1 : 0,
opendiscussion: $('input#opendiscussion').is(':checked') ? 1 : 0,
syntaxcoloring: $('input#syntaxcoloring').is(':checked') ? 1 : 0
};
$.post(scriptLocation(), data_to_send, 'json')
.error(function() {
showError('Data could not be sent (serveur error or not responding).');
})
.success(function(data) {
if (data.status == 0) {
stateExistingPaste();
var url = scriptLocation() + "?" + data.id + '#' + randomkey;
var deleteUrl = scriptLocation() + "?pasteid=" + data.id + '&deletetoken=' + data.deletetoken;
showStatus('');
$('div#pastelink').html('Your paste is <a id="pasteurl" href="' + url + '">' + url + '</a> <span id="copyhint">(Hit CTRL+C to copy)</span>');
$('div#deletelink').html('<a href="' + deleteUrl + '">Delete link</a>');
$('div#pasteresult').show();
selectText('pasteurl'); // We pre-select the link so that the user only has to CTRL+C the link.
setElementText($('div#cleartext'), $('textarea#message').val());
urls2links($('div#cleartext'));
// FIXME: Add option to remove syntax highlighting ?
if ($('input#syntaxcoloring').is(':checked')) applySyntaxColoring();
showStatus('');
}
else if (data.status==1) {
showError('Could not create paste: '+data.message);
}
else {
showError('Could not create paste.');
}
});
}
/** Text range selection.
* From: http://stackoverflow.com/questions/985272/jquery-selecting-text-in-an-element-akin-to-highlighting-with-your-mouse
* @param string element : Indentifier of the element to select (id="").
*/
function selectText(element) {
var doc = document
, text = doc.getElementById(element)
, range, selection
;
if (doc.body.createTextRange) { //ms
range = doc.body.createTextRange();
range.moveToElementText(text);
range.select();
} else if (window.getSelection) { //all others
selection = window.getSelection();
range = doc.createRange();
range.selectNodeContents(text);
selection.removeAllRanges();
selection.addRange(range);
}
}
/**
* Put the screen in "New paste" mode.
*/
function stateNewPaste() {
$('button#sendbutton').show();
$('button#clonebutton').hide();
$('button#rawtextbutton').hide();
$('div#expiration').show();
$('div#remainingtime').hide();
$('div#burnafterreadingoption').show();
$('div#opendisc').show();
$('div#syntaxcoloringoption').show();
$('button#newbutton').show();
$('div#pasteresult').hide();
$('textarea#message').text('');
$('textarea#message').show();
$('div#cleartext').hide();
$('div#message').focus();
$('div#discussion').hide();
}
/**
* Put the screen in "Existing paste" mode.
*/
function stateExistingPaste() {
$('button#sendbutton').hide();
// No "clone" for IE<10.
if ($('div#oldienotice').is(":visible")) {
$('button#clonebutton').hide();
}
else {
$('button#clonebutton').show();
}
$('button#rawtextbutton').show();
$('div#expiration').hide();
$('div#burnafterreadingoption').hide();
$('div#opendisc').hide();
$('div#syntaxcoloringoption').hide();
$('button#newbutton').show();
$('div#pasteresult').hide();
$('textarea#message').hide();
$('div#cleartext').show();
}
/** Return raw text
*/
function rawText()
{
var paste = $('div#cleartext').html();
var newDoc = document.open('text/html', 'replace');
newDoc.write('<pre>'+paste+'</pre>');
newDoc.close();
}
/**
* Clone the current paste.
*/
function clonePaste() {
stateNewPaste();
//Erase the id and the key in url
history.replaceState(document.title, document.title, scriptLocation());
showStatus('');
$('textarea#message').text($('div#cleartext').text());
}
/**
* Create a new paste.
*/
function newPaste() {
stateNewPaste();
showStatus('');
$('textarea#message').text('');
}
/**
* Display an error message
* (We use the same function for paste and reply to comments)
*/
function showError(message) {
$('div#status').addClass('errorMessage').text(message);
$('div#replystatus').addClass('errorMessage').text(message);
}
/**
* Display status
* (We use the same function for paste and reply to comments)
*
* @param string message : text to display
* @param boolean spin (optional) : tell if the "spinning" animation should be displayed.
*/
function showStatus(message, spin) {
$('div#replystatus').removeClass('errorMessage');
$('div#replystatus').text(message);
if (!message) {
$('div#status').html('&nbsp;');
return;
}
if (message == '') {
$('div#status').html('&nbsp;');
return;
}
$('div#status').removeClass('errorMessage');
$('div#status').text(message);
if (spin) {
var img = '<img src="img/busy.gif" style="width:16px;height:9px;margin:0px 4px 0px 0px;" />';
$('div#status').prepend(img);
$('div#replystatus').prepend(img);
}
}
/**
* Convert URLs to clickable links.
* URLs to handle:
* <code>
* magnet:?xt.1=urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C&xt.2=urn:sha1:TXGCZQTH26NL6OUQAJJPFALHG2LTGBC7
* http://localhost:8800/zero/?6f09182b8ea51997#WtLEUO5Epj9UHAV9JFs+6pUQZp13TuspAUjnF+iM+dM=
* http://user:password@localhost:8800/zero/?6f09182b8ea51997#WtLEUO5Epj9UHAV9JFs+6pUQZp13TuspAUjnF+iM+dM=
* </code>
*
* @param object element : a jQuery DOM element.
* @FIXME: add ppa & apt links.
*/
function urls2links(element) {
var re = /((http|https|ftp):\/\/[\w?=&.\/-;#@~%+-]+(?![\w\s?&.\/;#~%"=-]*>))/ig;
element.html(element.html().replace(re,'<a href="$1" rel="nofollow">$1</a>'));
var re = /((magnet):[\w?=&.\/-;#@~%+-]+)/ig;
element.html(element.html().replace(re,'<a href="$1">$1</a>'));
}
/**
* Return the deciphering key stored in anchor part of the URL
*/
function pageKey() {
var key = window.location.hash.substring(1); // Get key
// Some stupid web 2.0 services and redirectors add data AFTER the anchor
// (such as &utm_source=...).
// We will strip any additional data.
// First, strip everything after the equal sign (=) which signals end of base64 string.
i = key.indexOf('='); if (i>-1) { key = key.substring(0,i+1); }
// If the equal sign was not present, some parameters may remain:
i = key.indexOf('&'); if (i>-1) { key = key.substring(0,i); }
// Then add trailing equal sign if it's missing
if (key.charAt(key.length-1)!=='=') key+='=';
return key;
}
$(function() {
// If "burn after reading" is checked, disable discussion.
$('input#burnafterreading').change(function() {
if ($(this).is(':checked') ) {
$('div#opendisc').addClass('buttondisabled');
$('input#opendiscussion').attr({checked: false});
$('input#opendiscussion').attr('disabled',true);
}
else {
$('div#opendisc').removeClass('buttondisabled');
$('input#opendiscussion').removeAttr('disabled');
}
});
// Display status returned by php code if any (eg. Paste was properly deleted.)
if ($('div#status').text().length > 0) {
showStatus($('div#status').text(),false);
return;
}
$('div#status').html('&nbsp;'); // Keep line height even if content empty.
// Display an existing paste
if ($('div#cipherdata').text().length > 1) {
// Missing decryption key in URL ?
if (window.location.hash.length == 0) {
showError('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL ?)');
return;
}
// List of messages to display
var messages = jQuery.parseJSON($('div#cipherdata').text());
// Show proper elements on screen.
stateExistingPaste();
displayMessages(pageKey(), messages);
}
// Display error message from php code.
else if ($('div#errormessage').text().length>1) {
showError($('div#errormessage').text());
}
// Create a new paste.
else {
newPaste();
}
});

1043
tools/nobin/lib/rain.tpl.class.php Executable file

File diff suppressed because it is too large Load Diff

36
tools/nobin/lib/serversalt.php Executable file
View File

@@ -0,0 +1,36 @@
<?php
// Generate a large random hexadecimal salt.
function generateRandomSalt()
{
$randomSalt='';
if (function_exists("mcrypt_create_iv"))
{
$randomSalt = bin2hex(mcrypt_create_iv(256, MCRYPT_DEV_URANDOM));
}
else // fallback to mt_rand()
{
for($i=0;$i<16;$i++) { $randomSalt.=base_convert(mt_rand(),10,16); }
}
return $randomSalt;
}
/* Return this ZeroBin server salt.
This is a random string which is unique to each ZeroBin installation.
It is automatically created if not present.
Salt is used:
- to generate unique VizHash in discussions (which are not reproductible across ZeroBin servers)
- to generate unique deletion token (which are not re-usable across ZeroBin servers)
*/
function getServerSalt()
{
$saltfile = 'data/salt.php';
if (!is_file($saltfile))
file_put_contents($saltfile,'<?php /* |'.generateRandomSalt().'| */ ?>',LOCK_EX);
$items=explode('|',file_get_contents($saltfile));
return $items[1];
}
?>

View File

@@ -0,0 +1,142 @@
<?php
// VizHash_GD 0.0.4 beta ZeroBin 0.19
// Visual Hash implementation in php4+GD, stripped down and modified version for ZeroBin
// See: http://sebsauvage.net/wiki/doku.php?id=php:vizhash_gd
// This is free software under the zlib/libpng licence
// http://www.opensource.org/licenses/zlib-license.php
/* Example:
$vz = new vizhash16x16();
$data = $vz->generate('hello');
header('Content-type: image/png');
echo $data;
exit;
*/
require_once "serversalt.php";
class vizhash16x16
{
private $VALUES;
private $VALUES_INDEX;
private $width;
private $height;
private $salt;
function __construct()
{
$this->width=16;
$this->height=16;
$this->salt = getServerSalt();
}
// Generate a 16x16 png corresponding to $text.
// Input: $text (string)
// Output: PNG data. Or empty string if GD is not available.
function generate($text)
{
if (!function_exists('gd_info')) return '';
// We hash the input string.
$hash=hash('sha1',$text.$this->salt).hash('md5',$text.$this->salt);
$hash=$hash.strrev($hash); # more data to make graphics
// We convert the hash into an array of integers.
$this->VALUES=array();
for($i=0; $i<strlen($hash); $i=$i+2){ array_push($this->VALUES,hexdec(substr($hash,$i,2))); }
$this->VALUES_INDEX=0; // to walk the array.
// Then use these integers to drive the creation of an image.
$image = imagecreatetruecolor($this->width,$this->height);
$r0 = $this->getInt();$r=$r0;
$g0 = $this->getInt();$g=$g0;
$b0 = $this->getInt();$b=$b0;
// First, create an image with a specific gradient background.
$op='v'; if (($this->getInt()%2)==0) { $op='h'; };
$image = $this->degrade($image,$op,array($r0,$g0,$b0),array(0,0,0));
for($i=0; $i<7; $i=$i+1)
{
$action=$this->getInt();
$color = imagecolorallocate($image, $r,$g,$b);
$r = ($r0 + $this->getInt()/25)%256;
$g = ($g0 + $this->getInt()/25)%256;
$b = ($b0 + $this->getInt()/25)%256;
$r0=$r; $g0=$g; $b0=$b;
$this->drawshape($image,$action,$color);
}
$color = imagecolorallocate($image,$this->getInt(),$this->getInt(),$this->getInt());
$this->drawshape($image,$this->getInt(),$color);
ob_start();
imagepng($image);
$imagedata = ob_get_contents();
ob_end_clean();
imagedestroy($image);
return $imagedata;
}
private function getInt() // Returns a single integer from the $VALUES array (0...255)
{
$v= $this->VALUES[$this->VALUES_INDEX];
$this->VALUES_INDEX++;
$this->VALUES_INDEX %= count($this->VALUES); // Warp around the array
return $v;
}
private function getX() // Returns a single integer from the array (roughly mapped to image width)
{
return $this->width*$this->getInt()/256;
}
private function getY() // Returns a single integer from the array (roughly mapped to image height)
{
return $this->height*$this->getInt()/256;
}
# Gradient function taken from:
# http://www.supportduweb.com/scripts_tutoriaux-code-source-41-gd-faire-un-degrade-en-php-gd-fonction-degrade-imagerie.html
private function degrade($img,$direction,$color1,$color2)
{
if($direction=='h') { $size = imagesx($img); $sizeinv = imagesy($img); }
else { $size = imagesy($img); $sizeinv = imagesx($img);}
$diffs = array(
(($color2[0]-$color1[0])/$size),
(($color2[1]-$color1[1])/$size),
(($color2[2]-$color1[2])/$size)
);
for($i=0;$i<$size;$i++)
{
$r = $color1[0]+($diffs[0]*$i);
$g = $color1[1]+($diffs[1]*$i);
$b = $color1[2]+($diffs[2]*$i);
if($direction=='h') { imageline($img,$i,0,$i,$sizeinv,imagecolorallocate($img,$r,$g,$b)); }
else { imageline($img,0,$i,$sizeinv,$i,imagecolorallocate($img,$r,$g,$b)); }
}
return $img;
}
private function drawshape($image,$action,$color)
{
switch($action%7)
{
case 0:
ImageFilledRectangle ($image,$this->getX(),$this->getY(),$this->getX(),$this->getY(),$color);
break;
case 1:
case 2:
ImageFilledEllipse ($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(), $color);
break;
case 3:
$points = array($this->getX(), $this->getY(), $this->getX(), $this->getY(), $this->getX(), $this->getY(),$this->getX(), $this->getY());
ImageFilledPolygon ($image, $points, 4, $color);
break;
case 4:
case 5:
case 6:
$start=$this->getInt()*360/256; $end=$start+$this->getInt()*180/256;
ImageFilledArc ($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(),$start,$end,$color,IMG_ARC_PIE);
break;
}
}
}
?>

2
tools/nobin/tmp/index.php Executable file
View File

@@ -0,0 +1,2 @@
<?php
//Silence est d'or.

View File

@@ -0,0 +1,134 @@
<?php if(!class_exists('raintpl')){exit;}?><!DOCTYPE html>
<html lang="fr">
<head>
<title>ZeroBin - Comunic</title>
<meta name="robots" content="noindex" />
<link type="text/css" rel="stylesheet" href="css/zerobin-for-comunic.css" />
<script src="js/jquery.js"></script>
<script src="js/sjcl.js"></script>
<script src="js/base64.js"></script>
<script src="js/rawdeflate.js"></script>
<script src="js/rawinflate.js"></script>
<script src="js/zerobin-fr.js"></script>
<link type="text/css" rel="stylesheet" href="js/highlight.styles/monokai.css">
<script src="js/highlight.pack.js"></script>
<!-- Metro UI CSS 3.0 -->
<link type="text/css" rel="stylesheet" href="../3rdparty/metrouicss/css/metro.min.css" />
<!--[if lt IE 10]>
<style> body {padding-left:60px;padding-right:60px;} div#ienotice {display:block;} </style>
<![endif]-->
<!--[if lt IE 10]>
<style> div#ienotice {display:block; } div#oldienotice {display:block; } </style>
<![endif]-->
</head>
<body>
<!-- Barre de menu -->
<div class="app-bar" data-role="appbar">
<a class="app-bar-element" href="../">Outils</a>
<span class="app-bar-divider"></span>
<a class="app-bar-element" onClick="window.location.href=scriptLocation();return false;" >ZeroBin</a>
<a class="app-bar-element" href="../../">Retour &agrave; Comunic</a>
</div>
<div class="window info-zerobin">
<div class="window-caption">
<span class="window-caption-icon"><span class="mif-windows"></span></span>
<span class="window-caption-title">A propos de ZeroBin</span>
<span class="btn-close" onClick="this.parentNode.parentNode.style.visibility='hidden';"></span>
</div>
<div class="window-content" style="height: 100px">
ZeroBin est un service en ligne libre et minimaliste qui permet à nimporte qui de partager des textes de manière confidentielle et sécurisée.
Les données sont chiffrées/déchiffrées <i>dans le navigateur</i> en utilisant lalgorithme AES 256 bits.
Plus dinformations sur le <a href="http://sebsauvage.net/wiki/doku.php?id=php:zerobin">site du projet</a>.
</div>
</div>
<noscript><div class="nonworking">Zerobin requiert lactivation du Javascript pour fonctionner.<br>Désolé pour le désagrément.</div></noscript>
<div id="oldienotice" class="nonworking">Un navigateur web moderne est requis pour utiliser ZeroBin.</div>
<div id="ienotice">Vous utilisez encore Internet Explorer ? &nbsp;Rendez-vous service, basculez sur un navigateur web moderne :
<a href="http://www.mozilla.org/firefox/">Firefox (Recommand&eacute;)</a>,
<a href="http://www.opera.com/">Opera</a>,
<a href="http://www.google.com/chrome">Chrome</a>,
<a href="http://www.apple.com/safari">Safari</a>…
</div>
<!-- Containeur principal -->
<div class="container">
<!-- Affichage du status -->
<div id="status"><?php echo $STATUS;?></div>
<!-- Message d'erreur -->
<div id="errormessage" style="display:none"><?php echo htmlspecialchars( $ERRORMESSAGE );?></div>
<!-- Barre d'outils -->
<div id="toolbar">
<!-- Bouton de création d'un nouveau texte et de nettoyage -->
<button id="newbutton" class="button success" onclick="window.location.href=scriptLocation();return false;" style="display:none;"><img src="img/icon_new.png"/> Nouveau</button>
<!-- Bouton de confirmation d'envoi -->
<button id="sendbutton" class="button primary" onclick="send_data();return false;" style="display:none;"><img src="img/icon_send.png"/> Envoyer</button>
<!-- Bouton permettant de cloner le message actuel dans un nouveau -->
<button id="clonebutton" class="button danger" onclick="clonePaste();return false;" style="display:none;"><img src="img/icon_clone.png" /> Cloner</button>
<!-- Bouton permettant d'afficher le texte brut -->
<button id="rawtextbutton" class="button info" onclick="rawText();return false;" style="display:none; "><img src="img/icon_raw.png" width="15" height="15" style="padding:1px 0px 1px 0px;"/> Texte brut</button>
<!-- Définition d'une date d'expiration -->
<div id="expiration" class="input-control select" style="display:none;">
<select id="pasteExpiration" name="pasteExpiration">
<option value="5min">5 minutes</option>
<option value="10min">10 minutes</option>
<option value="1hour">1 heure</option>
<option value="1day">1 jour</option>
<option value="1week">1 semaine</option>
<option value="1month" selected="selected">Expiration : 1 mois</option>
<option value="1year">1 an</option>
<option value="never">Jamais</option>
</select>
</div>
<!-- Affichage du temps restant (si nécessaire) -->
<div id="remainingtime" style="display:none;"></div>
<!-- Détruire après la première lecture -->
<div id="burnafterreadingoption" class="button" style="display:none;">
<input type="checkbox" id="burnafterreading" name="burnafterreading" />
<label for="burnafterreading">Une seule lecture</label>
</div>
<!-- Bouton permettant la création d'une discussion -->
<div id="opendisc" class="button" style="display:none;">
<input type="checkbox" id="opendiscussion" name="opendiscussion" />
<label for="opendiscussion">Discussion</label>
</div>
<!-- Bouton permettant la coloration syntaxique -->
<div id="syntaxcoloringoption" class="button" style="display:none;">
<input type="checkbox" id="syntaxcoloring" name="syntaxcoloring" />
<label for="syntaxcoloring">Coloration syntaxique</label>
</div>
</div>
<div id="pasteresult" style="display:none;">
<div class="padding10 bg-emerald fg-white pastelink" id="pastelink"></div>
<div id="deletelink"></div>
</div>
<div id="cleartext" style="display:none;"></div>
<textarea id="message" name="message" cols="80" rows="25" style="display:none;"></textarea>
<div id="discussion" style="display:none;">
<h4>Discussion</h4>
<div id="comments"></div>
</div>
<div id="cipherdata" style="display:none;"><?php echo $CIPHERDATA;?></div>
</div>
</body>
</html>

134
tools/nobin/tpl/page.html Executable file
View File

@@ -0,0 +1,134 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<title>ZeroBin - Comunic</title>
<meta name="robots" content="noindex" />
<link type="text/css" rel="stylesheet" href="css/zerobin-for-comunic.css#" />
<script src="js/jquery.js#"></script>
<script src="js/sjcl.js#"></script>
<script src="js/base64.js#"></script>
<script src="js/rawdeflate.js#"></script>
<script src="js/rawinflate.js#"></script>
<script src="js/zerobin-fr.js#"></script>
<link type="text/css" rel="stylesheet" href="js/highlight.styles/monokai.css#">
<script src="js/highlight.pack.js#"></script>
<!-- Metro UI CSS 3.0 -->
<link type="text/css" rel="stylesheet" href="../3rdparty/metrouicss/css/metro.min.css#" />
<!--[if lt IE 10]>
<style> body {padding-left:60px;padding-right:60px;} div#ienotice {display:block;} </style>
<![endif]-->
<!--[if lt IE 10]>
<style> div#ienotice {display:block; } div#oldienotice {display:block; } </style>
<![endif]-->
</head>
<body>
<!-- Barre de menu -->
<div class="app-bar" data-role="appbar">
<a class="app-bar-element" href="../">Outils</a>
<span class="app-bar-divider"></span>
<a class="app-bar-element" onClick="window.location.href=scriptLocation();return false;" >ZeroBin</a>
<a class="app-bar-element" href="../../">Retour &agrave; Comunic</a>
</div>
<div class="window info-zerobin">
<div class="window-caption">
<span class="window-caption-icon"><span class="mif-windows"></span></span>
<span class="window-caption-title">A propos de ZeroBin</span>
<span class="btn-close" onClick="this.parentNode.parentNode.style.visibility='hidden';"></span>
</div>
<div class="window-content" style="height: 100px">
ZeroBin est un service en ligne libre et minimaliste qui permet à nimporte qui de partager des textes de manière confidentielle et sécurisée.
Les données sont chiffrées/déchiffrées <i>dans le navigateur</i> en utilisant lalgorithme AES 256 bits.
Plus dinformations sur le <a href="http://sebsauvage.net/wiki/doku.php?id=php:zerobin">site du projet</a>.
</div>
</div>
<noscript><div class="nonworking">Zerobin requiert lactivation du Javascript pour fonctionner.<br>Désolé pour le désagrément.</div></noscript>
<div id="oldienotice" class="nonworking">Un navigateur web moderne est requis pour utiliser ZeroBin.</div>
<div id="ienotice">Vous utilisez encore Internet Explorer ? &nbsp;Rendez-vous service, basculez sur un navigateur web moderne :
<a href="http://www.mozilla.org/firefox/">Firefox (Recommand&eacute;)</a>,
<a href="http://www.opera.com/">Opera</a>,
<a href="http://www.google.com/chrome">Chrome</a>,
<a href="http://www.apple.com/safari">Safari</a>
</div>
<!-- Containeur principal -->
<div class="container">
<!-- Affichage du status -->
<div id="status">{$STATUS}</div>
<!-- Message d'erreur -->
<div id="errormessage" style="display:none">{$ERRORMESSAGE|htmlspecialchars}</div>
<!-- Barre d'outils -->
<div id="toolbar">
<!-- Bouton de création d'un nouveau texte et de nettoyage -->
<button id="newbutton" class="button success" onclick="window.location.href=scriptLocation();return false;" style="display:none;"><img src="img/icon_new.png#"/> Nouveau</button>
<!-- Bouton de confirmation d'envoi -->
<button id="sendbutton" class="button primary" onclick="send_data();return false;" style="display:none;"><img src="img/icon_send.png#"/> Envoyer</button>
<!-- Bouton permettant de cloner le message actuel dans un nouveau -->
<button id="clonebutton" class="button danger" onclick="clonePaste();return false;" style="display:none;"><img src="img/icon_clone.png#" /> Cloner</button>
<!-- Bouton permettant d'afficher le texte brut -->
<button id="rawtextbutton" class="button info" onclick="rawText();return false;" style="display:none; "><img src="img/icon_raw.png#" width="15" height="15" style="padding:1px 0px 1px 0px;"/> Texte brut</button>
<!-- Définition d'une date d'expiration -->
<div id="expiration" class="input-control select" style="display:none;">
<select id="pasteExpiration" name="pasteExpiration">
<option value="5min">5 minutes</option>
<option value="10min">10 minutes</option>
<option value="1hour">1 heure</option>
<option value="1day">1 jour</option>
<option value="1week">1 semaine</option>
<option value="1month" selected="selected">Expiration : 1 mois</option>
<option value="1year">1 an</option>
<option value="never">Jamais</option>
</select>
</div>
<!-- Affichage du temps restant (si nécessaire) -->
<div id="remainingtime" style="display:none;"></div>
<!-- Détruire après la première lecture -->
<div id="burnafterreadingoption" class="button" style="display:none;">
<input type="checkbox" id="burnafterreading" name="burnafterreading" />
<label for="burnafterreading">Une seule lecture</label>
</div>
<!-- Bouton permettant la création d'une discussion -->
<div id="opendisc" class="button" style="display:none;">
<input type="checkbox" id="opendiscussion" name="opendiscussion" />
<label for="opendiscussion">Discussion</label>
</div>
<!-- Bouton permettant la coloration syntaxique -->
<div id="syntaxcoloringoption" class="button" style="display:none;">
<input type="checkbox" id="syntaxcoloring" name="syntaxcoloring" />
<label for="syntaxcoloring">Coloration syntaxique</label>
</div>
</div>
<div id="pasteresult" style="display:none;">
<div class="padding10 bg-emerald fg-white pastelink" id="pastelink"></div>
<div id="deletelink"></div>
</div>
<div id="cleartext" style="display:none;"></div>
<textarea id="message" name="message" cols="80" rows="25" style="display:none;"></textarea>
<div id="discussion" style="display:none;">
<h4>Discussion</h4>
<div id="comments"></div>
</div>
<div id="cipherdata" style="display:none;">{$CIPHERDATA}</div>
</div>
</body>
</html>

BIN
tools/speaker/.DS_Store vendored Executable file

Binary file not shown.

133
tools/speaker/index.php Executable file
View File

@@ -0,0 +1,133 @@
<!DOCTYPE html>
<html>
<head>
<title>Speaker.js - Comunic</title>
<!-- Styles de la page -->
<style type="text/css">
body {
text-align: justify;
}
#speaker_area {
text-align: center;
margin-top: 17%;
background-color: rgba(27, 161, 226, 0.44);
padding: 20px;
border-radius: 5px;
}
.texte_parole {
width: 55% !important;
}
</style>
<!-- Inclusion de Speak.js -->
<script type="text/javascript" src="js/mespeak.js"></script>
<!-- Initialisation de Speak.js -->
<script type="text/javascript">
//Chargement de la voix française
meSpeak.loadVoice("voices/fr.json");
//Chargement de la configuration
meSpeak.loadConfig("js/mespeak_config.json");
//Permet de forcer le telechargement d'un fichier en JS
function forceDownload(fileURL, fileName) {
// non-IE
if (!window.ActiveXObject) {
var save = document.createElement('a');
save.href = fileURL;
save.target = '_blank';
save.download = fileName || 'unknown';
var event = document.createEvent('Event');
event.initEvent('click', true, true);
save.dispatchEvent(event);
(window.URL || window.webkitURL).revokeObjectURL(save.href);
}
// for IE
else if ( !! window.ActiveXObject && document.execCommand) {
var _window = window.open(fileURL, '_blank');
_window.document.close();
_window.document.execCommand('SaveAs', true, fileName || fileURL)
_window.close();
}
}
function gospeak() {
//Récupération du texte de parole
texte = document.getElementById('text_speak').value;
//On vérifie si il faut utiliser une voix de femme ou non
use_female_voice = document.getElementById('enable_female_voice').checked;
//On vérifie si il faut télécharger le résultat ou non
download_result = document.getElementById('download_result').checked;
if(use_female_voice == false)
{
//Utilisation d'une voix d'homme
var variante = "m3";
}
else
{
//Utilisation d'une voix de femme
var variante = "f5";
}
if(download_result == false)
{
//On parle
meSpeak.speak(texte, {voice: "fr", variant: variante});
}
else
{
//Préparer le fichier pour le téléchargement puis le télécharger
var myDataUrl = meSpeak.speak(texte, {voice: "fr", variant: variante, 'rawdata': 'data-url' });
window.open(myDataUrl);
}
}
</script>
</head>
<body>
<?php $sub_folder = true; include('../menu.php'); ?>
<div class="container">
<h1><a href="../" class="nav-button transform"><span></span></a>&nbsp;Speaker.js</h1>
<p>Ce logiciel web vous permet d'effectuer la synth&egrave;se vocale de ce que vous saisissez dans le champ de texte. Note: Gr&acirc;ce &agrave; la puissance de Javascript, les paroles sont transform&eacute;es en fichier vocal localement sur votre navigateur. Votre confidentialit&eacute; est ainsi respect&eacute;e. Ce syst&egrave;me est bas&eacute; sur le projet meSpeak.js, dont le site est <a href="http://www.masswerk.at/mespeak/" target="_blank">accessible ici</a>.</p>
<!-- Zone de gestion de la parole -->
<div id="speaker_area">
<!-- Saisie la parole -->
<div class="input-control text texte_parole">
<input type="text" placeholder="Saissez ici votre texte" id="text_speak" />
</div>
&nbsp;
<!-- Activer ou non la voix de femme -->
<label class="switch">
<input type="checkbox" id="enable_female_voice"/>
<span class="check"></span>
Voix de femme
</label>
<!-- Télécharger ou non -->
<label class="switch">
<input type="checkbox" id="download_result"/>
<span class="check"></span>
T&eacute;l&eacute;charger
</label>
<!-- Parler! -->
<button class="button" onClick="gospeak();">
<span class="mif-volume-high"></span>
</button>
</div>
</div>
</body>
</html>

84282
tools/speaker/js/mespeak.full.js Executable file

File diff suppressed because one or more lines are too long

7353
tools/speaker/js/mespeak.js Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

84282
tools/speaker/mespeak.full.js Executable file

File diff suppressed because one or more lines are too long

7353
tools/speaker/mespeak.js Executable file

File diff suppressed because one or more lines are too long

BIN
tools/speaker/msie_flashFallback/as3/.DS_Store vendored Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,68 @@
/*
meSpeakFallback.as
An experimental fallback option for meSpeak to play wav files
Wav-files are sent as a plain array of uint 8-bit data via ExternalInterface
JS interface:
meSpeakFallback.play( <wav-array> );
meSpeak.setVolume( value ) // 0 >= value <= 1
Handshake: calls JS function 'meSpeakFallbackHandshake()', when initialized and ready
Norbert Landsteiner, www.masswerk.at, July 2013
*/
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.external.ExternalInterface;
import flash.media.Sound;
import flash.media.SoundTransform;
import flash.utils.ByteArray;
import flash.utils.setTimeout;
import org.as3wavsound.WavSound;
import org.as3wavsound.WavSoundChannel;
public class meSpeakFallback extends Sprite
{
private var sndTransform:SoundTransform=new SoundTransform(1, 0);
public function meSpeakFallback()
{
initExtIF();
}
private function initExtIF():void {
var available:Boolean=false;
try {
if (ExternalInterface.available) {
ExternalInterface.addCallback("play", play);
ExternalInterface.addCallback("setVolume", setVolume);
ExternalInterface.call("meSpeakFallbackHandshake");
available=true;
}
}
catch (e:Error) {}
if (!available) setTimeout(initExtIF, 100);
}
public function setVolume(v:Number=0):void {
if (v>=0 && v<=1) sndTransform.volume=v;
}
public function play(data:Array=null):void {
if (!data) return;
var l:uint=data.length;
if (!l) return;
// copy data to a ByteArray (oops: time, memory!)
var ba:ByteArray=new ByteArray();
ba.length=l;
for (var i:uint=0; i<l; i++) ba.writeByte(data[i]);
// play sound with global volume
var snd:WavSound = new WavSound(ba);
var chnl:WavSoundChannel=snd.play(0, 0, sndTransform);
}
}
}

Binary file not shown.

View File

@@ -0,0 +1,201 @@
/*
* --------------------------------------
* Benny Bottema -- WavSound Sound adaption
* http://blog.projectnibble.org/
* --------------------------------------
* sazameki -- audio manipulating library
* http://sazameki.org/
* --------------------------------------
*
* - developed by:
* Benny Bottema
* blog.projectnibble.org
* hosted by:
* Google Code (code.google.com)
* code.google.com/p/as3wavsound/
*
* - audio library in its original state developed by:
* Takaaki Yamazaki
* www.zkdesign.jp
* hosted by:
* Spark project (www.libspark.org)
* www.libspark.org/svn/as3/sazameki/branches/fp10/
*/
/*
* Licensed under the MIT License
*
* Copyright (c) 2008 Takaaki Yamazaki
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.as3wavsound {
import flash.media.SoundTransform;
import flash.utils.ByteArray;
import org.as3wavsound.sazameki.core.AudioSamples;
import org.as3wavsound.sazameki.core.AudioSetting;
import org.as3wavsound.sazameki.format.wav.Wav;
/**
* Sound extension that directly plays WAVE data. Also backwards compatible with
* MP3's played through the load() function. This class acts as facade to loading,
* extracting, decoding and playing wav sound data and represents a single sound.
*
* This class is analog to Adobe's Sound class and is designed to function the same
* way.
*
* Usage:
* Simply embed .wav files as you would mp3's and play with this Sound class.
* Make sure you provide mimetype 'application/octet-stream' when embedding to
* ensure Flash embeds the data as ByteArray.
*
* Example:
* [Embed(source = "drumloop.wav", mimeType = "application/octet-stream")]
* public const DrumLoop:Class;
* public const rain:WavSound = new WavSound(new DrumLoop() as ByteArray);
*
*
* @author Benny Bottema
*/
public class WavSound {
// the master Sound player, which mixes all playing WavSound samples on any given moment
private static const player:WavSoundPlayer = new WavSoundPlayer();
// length of the original encoded wav data
private var _bytesTotal:Number;
// extracted sound data for mixing
private var _samples:AudioSamples;
// each sound can be configured to be played mono/stereo using AudioSetting
private var _playbackSettings:AudioSetting;
// calculated length of the entire sound in milliseconds, made global to avoid recalculating all the time
private var _length:Number;
/**
* Constructor: loads wavdata using load().
*
* loads WAVE data and decodes it into playable samples. Finally calculates
* the length of the sound in milliseconds.
*
* @param wavData A ByteArray containing uncmopressed wav data.
* @param audioSettings An optional playback configuration (mono/stereo,
* sample rate and bit rate).
*/
public function WavSound(wavData:ByteArray, audioSettings:AudioSetting = null) {
load(wavData, audioSettings);
}
/**
* Key function: loads WAVE data and decodes it into playable samples.
* Finally calculates the length of the sound in milliseconds.
*
* @param wavData The byte array that is the embedded .was file (octet-stream).
* @param audioSettings Optional settings for playback (samplerate will enforced
* if it differs from the .wav header data or header is missing).
* @see Wav#decode(ByteArray)
*/
internal function load(wavData:ByteArray, audioSettings:AudioSetting = null): void {
this._bytesTotal = wavData.length;
this._samples = new Wav().decode(wavData, audioSettings);
this._playbackSettings = (audioSettings != null) ? audioSettings : new AudioSetting();
this._length = samples.length / samples.setting.sampleRate * 1000;
}
/**
* See Adobe's Sound.play(): http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/Sound.html#play().
*
* Playback function that performs the following tasks:
*
* - calculates the startingPhase, bases on startTime in ms.
* - initializes loopsLeft variable
* - adds the playing channel in combination with its originating WavSound to the playingWavSounds
*
* @param startTime The starting time in milliseconds, applies to each loop (as with regular MP3 Sounds).
* @param loops The number of loops to take in *addition* to the default playback (loops == 2 means 3 playthroughs).
* @param sndTransform An optional soundtransform to apply for playback that controls volume and panning.
* @return The SoundChannel used for playing back the sound (and stopping the sound).
*/
public function play(startTime:Number = 0, loops:int = 0, sndTransform:SoundTransform = null): WavSoundChannel {
return player.play(this, startTime, loops, sndTransform);
}
/**
* No idea if this works. Alpha state. Read up on Sound.extract():
* http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/Sound.html#extract()
*
* Apparently, some people have used this succesfully, see comment 1 on Issue 11:
* http://code.google.com/p/as3wavsound/issues/detail?id=11#c1
*/
public function extract(target:ByteArray, length:Number, startPosition:Number = -1): Number {
var start:Number = Math.max(startPosition, 0);
var end:Number = Math.min(length, samples.length);
for (var i:Number = start; i < end; i++) {
target.writeFloat(samples.left[i]);
if (samples.setting.channels == 2) {
target.writeFloat(samples.right[i]);
} else {
target.writeFloat(samples.left[i]);
}
}
return samples.length;
}
/**
* Returns the total bytes of the wavData a WavSound was created with.
*
* Note:
* This function is probably legacy, since we're not extending Adobe's
* Sound anymore (backwards compatibility was dropped in v0.7.
*/
public function get bytesLoaded () : uint {
return _bytesTotal;
}
/**
* Returns the total bytes of the wavData a WavSound was created with.
*
* Note:
* This function is probably legacy, since we're not extending Adobe's
* Sound anymore (backwards compatibility was dropped in v0.7.
*/
public function get bytesTotal () : int {
return _bytesTotal;
}
/**
* Returns the total length of the sound in milliseconds.
*/
public function get length() : Number {
return _length;
}
internal function get samples():AudioSamples {
return _samples;
}
/**
* _playbackSettings is set when the load() function is called.
*/
internal function get playbackSettings():AudioSetting {
return _playbackSettings;
}
}
}

View File

@@ -0,0 +1,229 @@
/*
* --------------------------------------
* Benny Bottema -- WavSound Sound adaption
* http://blog.projectnibble.org/
* --------------------------------------
* sazameki -- audio manipulating library
* http://sazameki.org/
* --------------------------------------
*
* - developed by:
* Benny Bottema
* blog.projectnibble.org
* hosted by:
* Google Code (code.google.com)
* code.google.com/p/as3wavsound/
*
* - audio library in its original state developed by:
* Takaaki Yamazaki
* www.zkdesign.jp
* hosted by:
* Spark project (www.libspark.org)
* www.libspark.org/svn/as3/sazameki/branches/fp10/
*/
/*
* Licensed under the MIT License
*
* Copyright (c) 2008 Takaaki Yamazaki
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.as3wavsound {
import flash.events.EventDispatcher;
import flash.media.SoundChannel;
import flash.events.Event;
import flash.media.SoundTransform;
import org.as3wavsound.sazameki.core.AudioSamples;
import org.as3wavsound.WavSound;
/**
* Used to keep track of open channels during playback. Each channel represents
* an 'instance' of a sound and so each channel is responsible for its own mixing.
*
* The WavSound class uses the WavSoundPlayer to play instances of itself and
* returns the WavSoundChannel returned by the player.
*
* Also, the WavSoundPlayer uses the buffer() function to make the playing WavSoundChannel
* mix its own samples into the master buffer.
*
* Dispatches the Event.SOUND_COMPLETE event when the last sample has been mixed
* into the master buffer.
*
* Also see buffer().
*
* @author Benny Bottema
*/
public class WavSoundChannel extends EventDispatcher {
/*
* creation-time information
*/
// The player to delegate play() stop() requests to.
private var player:WavSoundPlayer;
// a WavSound currently playing back on this channel instance
// (there can be mutliple instances with the same WavSound).
private var _wavSound:WavSound;
// works the same as Adobe's SoundChannel.soundTransform
private var _soundTransform:SoundTransform = new SoundTransform();
/*
* play-time information *per WavSound instance*
*/
// starting phase if not at the beginning, made global to avoid recalculating all the time
private var startPhase:Number;
// current phase of the sound, basically matches a single current sample frame for each WavSound
private var phase:Number = 0;
// the current avarage volume of samples buffered to the left audiochannel
private var _leftPeak:Number = 0;
// the current avarage volume of samples buffered to the right audiochannel
private var _rightPeak:Number = 0;
// how many loops we need to buffer
private var loopsLeft:Number;
// indicates if the phase has reached total sample count and no loops are left
private var finished:Boolean;
/**
* Constructor: pre-calculates starting phase (and performs some validation for this), see init().
*/
public function WavSoundChannel(player:WavSoundPlayer, wavSound:WavSound, startTime:Number, loops:int, soundTransform:SoundTransform) {
this.player = player;
this._wavSound = wavSound;
if (soundTransform != null) {
this._soundTransform = soundTransform;
}
init(startTime, loops);
}
/**
* Calculates and validates the starting time. Starting time in milliseconds is converted into
* sample position and then marked as starting phase.
*
* Also resets finished state and sets 'loopsLeft' equal to the given 'loops' value.
*/
internal function init(startTime:Number, loops:int):void {
var startPositionInMillis:Number = Math.floor(startTime);
var maxPositionInMillis:Number = Math.floor(_wavSound.length);
if (startPositionInMillis > maxPositionInMillis) {
throw new Error("startTime greater than sound's length, max startTime is " + maxPositionInMillis);
}
phase = startPhase = Math.floor(startPositionInMillis * _wavSound.samples.length / _wavSound.length);
finished = false;
loopsLeft = loops;
}
/**
* Tells the WavsoundPlayer to stop this specific SoundWavChannel instance.
*/
public function stop():void {
player.stop(this);
}
/**
* Called from WavSoundPlayer when the player is ready to mix new samples into the master
* sample buffer.
*
* Fills a target samplebuffer with (optionally transformed) samples from the current
* WavSoundChannel instance.
*
* Keeps filling the buffer until the last samples are buffered or until the buffersize is
* reached. When the buffer is full, phase and loopsLeft keep track of how which samples
* still need to be buffered in the next buffering cycle (when this method is called again).
*
* @param sampleBuffer The target buffer to mix in the current (transformed) samples.
* @param soundTransform The soundtransform that belongs to a single channel being played
* (containing volume, panning etc.).
*/
internal function buffer(sampleBuffer:AudioSamples):void {
// calculate volume and panning
var volume: Number = (_soundTransform.volume / 1);
var volumeLeft: Number = volume * (1 - _soundTransform.pan) / 2;
var volumeRight: Number = volume * (1 + _soundTransform.pan) / 2;
// channel settings
var needRightChannel:Boolean = _wavSound.playbackSettings.channels == 2;
var hasRightChannel:Boolean = _wavSound.samples.setting.channels == 2;
// extra references to avoid excessive getter calls in the following
// for-loop (it appeares CPU is being hogged otherwise)
var samplesLength:Number = _wavSound.samples.length;
var samplesLeft:Vector.<Number> = _wavSound.samples.left;
var samplesRight:Vector.<Number> = _wavSound.samples.right;
var sampleBufferLength:Number = sampleBuffer.length;
var sampleBufferLeft:Vector.<Number> = sampleBuffer.left;
var sampleBufferRight:Vector.<Number> = sampleBuffer.right;
var leftPeakRecord:Number = 0;
var rightPeakRecord:Number = 0;
// finally, mix the samples in the master sample buffer
if (!finished) {
for (var i:int = 0; i < sampleBufferLength; i++) {
if (!finished) {
// write (transformed) samples to buffer
var sampleLeft:Number = samplesLeft[phase] * volumeLeft;
sampleBufferLeft[i] += sampleLeft;
leftPeakRecord += sampleLeft;
var channelValue:Number = ((needRightChannel && hasRightChannel) ? samplesRight[phase] : samplesLeft[phase]);
var sampleRight:Number = channelValue * volumeRight;
sampleBufferRight[i] += sampleRight;
rightPeakRecord += sampleRight;
// check playing and looping state
if (++phase >= samplesLength) {
phase = startPhase;
finished = loopsLeft-- == 0;
}
}
}
if (finished) {
dispatchEvent(new Event(Event.SOUND_COMPLETE));
}
}
_leftPeak = leftPeakRecord / sampleBufferLength;
_rightPeak = rightPeakRecord / sampleBufferLength
}
public function get leftPeak(): Number {
return _leftPeak;
}
public function get rightPeak(): Number {
return _rightPeak;
}
/**
* Returns the current position in milliseconds:
*
* phase * wavSound.length / wavSound.samples.length
*/
public function get position(): Number {
return phase * _wavSound.length / _wavSound.samples.length;
}
public function get soundTransform():SoundTransform {
return _soundTransform;
}
}
}

View File

@@ -0,0 +1,160 @@
/*
* --------------------------------------
* Benny Bottema -- WavSound Sound adaption
* http://blog.projectnibble.org/
* --------------------------------------
* sazameki -- audio manipulating library
* http://sazameki.org/
* --------------------------------------
*
* - developed by:
* Benny Bottema
* blog.projectnibble.org
* hosted by:
* Google Code (code.google.com)
* code.google.com/p/as3wavsound/
*
* - audio library in its original state developed by:
* Takaaki Yamazaki
* www.zkdesign.jp
* hosted by:
* Spark project (www.libspark.org)
* www.libspark.org/svn/as3/sazameki/branches/fp10/
*/
/*
* Licensed under the MIT License
*
* Copyright (c) 2008 Takaaki Yamazaki
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.as3wavsound {
import flash.events.SampleDataEvent;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundTransform;
import flash.net.URLRequest;
import flash.utils.ByteArray;
import org.as3wavsound.sazameki.core.AudioSamples;
import org.as3wavsound.sazameki.core.AudioSetting;
import org.as3wavsound.WavSoundChannel;
/**
* This player is used by WavSound instances to relay play() calls to and
* return the resulting WavSoundChannel instances.
*
* This player is used by WavSoundChannel instances to relay stop() calls to.
*
* This player contains a single Sound object which acts as the master buffer in which
* all playing sounds are mixed to. This is done to reduce cpu / memory footprint. The
* player will loop through all playing WavSoundChannel instances and call
* buffer(masterSampleBuffer) function on each, before writing the end result to the
* sound card's outputstream.
*
* @author Benny Bottema
*/
internal class WavSoundPlayer {
// The size of the master sample buffer used for playback.
// Too small: the sound will have a jittery playback.
// Too big: the sound will have high latencies (loading, stopping, playing, etc.).
public static var MAX_BUFFERSIZE:Number = 8192;
// the master samples buffer in which all seperate Wavsounds are mixed into, always stereo at 44100Hz and bitrate 16
private const sampleBuffer:AudioSamples = new AudioSamples(new AudioSetting(), MAX_BUFFERSIZE);
// a list of all WavSound currenctly in playing mode
private const playingWavSounds:Vector.<WavSoundChannel> = new Vector.<WavSoundChannel>();
// the singular playback Sound with which all other WavSounds are played back
private const player:Sound = configurePlayer();
/**
* Static initializer: creates, configures and a sound player using the 'sample
* data event technique'. Until play() has been called on a WavSound, nothing is
* audible, because playingWavSounds will still be empty.
*
* Also see: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/SampleDataEvent.html
*/
private function configurePlayer():Sound {
var player:Sound = new Sound();
player.addEventListener(SampleDataEvent.SAMPLE_DATA, onSamplesCallback);
player.play();
return player;
}
/**
* Creates WavSoundChannel and adds it to the list of currently playing channels
* (which are mixed into the master sample buffer).
*
* This function is called by WavSound instances which returns the new WavSoundChannel
* instance to the user.
*/
internal function play(sound:WavSound, startTime:Number, loops:int, sndTransform:SoundTransform):WavSoundChannel {
var channel:WavSoundChannel = new WavSoundChannel(this, sound, startTime, loops, sndTransform);
playingWavSounds.push(channel);
return channel;
}
/**
* Remove a specific currently playing channel, so that its samples won't be
* mixed to the master sample buffer anymore and therefor playback will stop.
*/
internal function stop(channel:WavSoundChannel):void {
for each (var playingWavSound:WavSoundChannel in playingWavSounds) {
if (playingWavSound == channel) {
playingWavSounds.splice(playingWavSounds.lastIndexOf(playingWavSound), 1);
}
}
}
/**
* The heartbeat of the WavSound approach, invoked by the master Sound object.
*
* This function handles the SampleDataEvent to mix all playing sounds in playingWavSounds
* into the Sound's buffer. For each playing WavSoundChannel instance, the player will call
* the channel's buffer() function to have it mix itself into the master sample buffer.
* Finally, the resulting master buffer is written to the event's output stream.
*
* Also see: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/SampleDataEvent.html
*
* @param event Contains the soundcard outputstream to mix sound samples into.
*/
private function onSamplesCallback(event:SampleDataEvent):void {
// clear the buffer
sampleBuffer.clearSamples();
// have all channels mix their into the master sample buffer
for each (var playingWavSound:WavSoundChannel in playingWavSounds) {
playingWavSound.buffer(sampleBuffer);
}
// extra references to avoid excessive getter calls in the following
// for-loop (it appeares CPU is being hogged otherwise)
var outputStream:ByteArray = event.data;
var samplesLength:Number = sampleBuffer.length;
var samplesLeft:Vector.<Number> = sampleBuffer.left;
var samplesRight:Vector.<Number> = sampleBuffer.right;
// write all mixed samples to the sound's outputstream
for (var i:int = 0; i < samplesLength; i++) {
outputStream.writeFloat(samplesLeft[i]);
outputStream.writeFloat(samplesRight[i]);
}
}
}
}

View File

@@ -0,0 +1,57 @@
package org.as3wavsound.sazameki.core {
/**
* Contains lists of samples -left and optionally right- decoded from a
* WAVE ByteArray or manually mixed samples.
*
* Also contains a reference to an AudioSetting instance associated by
* this samples container.
*
* @author Takaaki Yamazaki(zk design),
* @author Benny Bottema (modified, optimized and cleaned up code)
*/
public class AudioSamples {
public var _left:Vector.<Number>;
public var _right:Vector.<Number>;
private var _setting:AudioSetting;
/**
* @param length Can be zero when decoding WAVE data, or a fixed buffer
* size when mixing to a Sound's outputstream.
*/
public function AudioSamples(setting:AudioSetting, length:Number = 0) {
this._setting = setting;
this._left = new Vector.<Number>(length, length > 0);
if (setting.channels == 2) {
this._right = new Vector.<Number>(length, length > 0);
}
}
/**
* Always resets length to its former state. Don't call this after creating
* an instance of AudioSamples, or its length is always zero.
*/
public function clearSamples():void {
_left = new Vector.<Number>(length, true);
if (setting.channels == 2) {
_right = new Vector.<Number>(length, true);
}
}
public function get length():int {
return left.length;
}
public function get setting():AudioSetting {
return _setting;
}
public function get left():Vector.<Number> {
return _left;
}
public function get right():Vector.<Number> {
return _right;
}
}
}

View File

@@ -0,0 +1,50 @@
package org.as3wavsound.sazameki.core {
/**
* Contains a sound's playback configuration, such as mono / stereo,
* sample rate and bit rate.
*
* @author Takaaki Yamazaki(zk design),
* @author Benny Bottema (modified, optimized and cleaned up code)
*/
public class AudioSetting {
// 1 or 2
private var _channels:uint;
// 11025, 22050 or 44100
private var _sampleRate:uint;
// 8 or 16
private var _bitRate:uint;
/**
* Constructor: performs some validations on the values being passed in.
*/
public function AudioSetting(channels:uint = 2, sampleRate:uint = 44100, bitRate:uint = 16) {
if (sampleRate != 44100 && sampleRate != 22050 && sampleRate != 11025) {
throw new Error("bad sample rate. sample rate must be 44100, 22050 or 11025");
}
if (channels != 1 && channels != 2) {
throw new Error("channels must be 1 or 2");
}
if (bitRate != 16 && bitRate != 8) {
throw new Error("bitRate must be 8 or 16");
}
_channels=channels;
_sampleRate=sampleRate;
_bitRate=bitRate;
}
public function get channels():uint{
return _channels;
}
public function get sampleRate():uint{
return _sampleRate;
}
public function get bitRate():uint{
return _bitRate;
}
}
}

View File

@@ -0,0 +1,48 @@
package org.as3wavsound.sazameki.format.riff {
import flash.utils.ByteArray;
import flash.utils.Endian;
/**
* RIFF Chunk class
*
* @author Takaaki Yamazaki(zk design),
* @author Benny Bottema (modified, optimized and cleaned up code)
*/
public class Chunk {
protected const ENDIAN:String = Endian.LITTLE_ENDIAN;
protected var _id:String;
public function Chunk(id:String) {
this.id = id;
}
public function set id(value:String):void {
if (value.length > 4) {
value = value.substr(0, 4);
} else if (value.length < 4) {
while (value.length < 4) {
value += " ";
}
}
_id = value;
}
public function get id():String {
return _id;
}
public function toByteArray():ByteArray {
var result:ByteArray = new ByteArray();
result.endian = ENDIAN;
result.writeUTFBytes(_id);
var data:ByteArray = encodeData();
result.writeUnsignedInt(data.length);
result.writeBytes(data);
return result;
}
protected function encodeData():ByteArray {
throw new Error("'encodeData()' method must be overriden");
}
}
}

View File

@@ -0,0 +1,75 @@
package org.as3wavsound.sazameki.format.riff {
import flash.utils.ByteArray;
/**
* ...
*
* @author Takaaki Yamazaki(zk design),
* @author Benny Bottema (modified, optimized and cleaned up code)
*/
public class LIST extends Chunk {
protected var _type:String;
protected var _chunks:Vector.<Chunk>;
public function LIST(type:String) {
this.type = type;
super("LIST");
}
public function set type(value:String):void {
if (value.length > 4) {
value = value.substr(0, 4);
} else if (value.length < 4) {
while (value.length < 4) {
value += " ";
}
}
_type = value;
}
public function get type():String {
return _type;
}
override protected function encodeData():ByteArray {
var result:ByteArray = new ByteArray();
result.writeUTFBytes(_type);
for (var i:int = 0; i < _chunks.length; i++) {
result.writeBytes(_chunks[i].toByteArray());
}
return result;
}
protected function splitList(bytes:ByteArray):Object {
var obj:Object = new Object();
bytes.position = 0;
bytes.endian = ENDIAN;
if (bytes.readUTFBytes(4) == 'RIFF') {
bytes.readInt();
bytes.readUTFBytes(4);//type
} else {
bytes.position = 0;
}
while (bytes.position < bytes.length) {
var currentName:String = bytes.readUTFBytes(4);
var current:int = bytes.readInt();
if (currentName == 'LIST') {
currentName = bytes.readUTFBytes(4);
current -= 4;
}
var tmpByte:ByteArray = new ByteArray();
bytes.readBytes(tmpByte, 0, current);
if (current % 2 == 1) {
bytes.readByte();
}
obj[currentName] = tmpByte;
}
return obj;
}
}
}

View File

@@ -0,0 +1,15 @@
package org.as3wavsound.sazameki.format.riff {
/**
* ...
*
* @author Takaaki Yamazaki(zk design),
* @author Benny Bottema (modified, optimized and cleaned up code)
*/
public class RIFF extends LIST {
public function RIFF(type:String) {
super(type);
id = 'RIFF';
}
}
}

View File

@@ -0,0 +1,106 @@
package org.as3wavsound.sazameki.format.wav {
import org.as3wavsound.sazameki.core.AudioSamples;
import org.as3wavsound.sazameki.core.AudioSetting;
import org.as3wavsound.sazameki.format.riff.Chunk;
import org.as3wavsound.sazameki.format.riff.RIFF;
import org.as3wavsound.sazameki.format.wav.chunk.WavdataChunk;
import org.as3wavsound.sazameki.format.wav.chunk.WavfmtChunk;
import flash.utils.ByteArray;
/**
* The WAVE decoder used for playing back wav files.
*
* @author Takaaki Yamazaki(zk design),
* @author Benny Bottema (modified, optimized and cleaned up code)
*/
public class Wav extends RIFF {
public function Wav() {
super('WAVE');
}
public function encode(samples:AudioSamples):ByteArray {
var fmt:WavfmtChunk = new WavfmtChunk();
var data:WavdataChunk = new WavdataChunk();
_chunks = new Vector.<Chunk>;
_chunks.push(fmt);
_chunks.push(data);
data.setAudioData(samples);
fmt.setSetting(samples.setting);
return toByteArray();
}
public function decode(wavData:ByteArray, setting:AudioSetting):AudioSamples {
var obj:Object = splitList(wavData);
var data:AudioSamples;
var relevantSetting:AudioSetting = setting;
if (relevantSetting == null && obj['fmt ']) {
relevantSetting = new WavfmtChunk().decodeData(obj['fmt '] as ByteArray);
}
if (obj['fmt '] && obj['data']) {
data = new WavdataChunk().decodeData(obj['data'] as ByteArray, relevantSetting);
} else {
data = new WavdataChunk().decodeData(wavData, relevantSetting);
}
var needsResampling:Boolean = relevantSetting != null && relevantSetting.sampleRate != 44100;
return (needsResampling) ? resampleAudioSamples(data, relevantSetting.sampleRate) : data;
}
/**
* Resamples the given audio samples from a given sample rate to a target sample rate (or default 44100).
*
* @author Simion Medvedi (medvedisimion@gmail.com)
* @author Benny Bottema (sanitized code and added support for stereo resampling)
*/
private function resampleAudioSamples(data:AudioSamples, sourceRate:int, targetRate:int = 44100):AudioSamples {
var newSize:int = data.length * targetRate / sourceRate;
var newData:AudioSamples = new AudioSamples(new AudioSetting(data.setting.channels, targetRate, 16), newSize);
resampleSamples(data.left, newData.left, newSize, sourceRate, targetRate);
// playback buffering in WavSoundChannel will take care of a possibly missing right channel
if (data.setting.channels == 2) {
resampleSamples(data.right, newData.right, newSize, sourceRate, targetRate);
}
return newData;
}
/**
* Resamples the given audio samples from a given sample rate to a target sample rate (or default 44100).
*
* @author Simion Medvedi (medvedisimion@gmail.com)
* @author Benny Bottema (sanitized code)
*/
private function resampleSamples(sourceSamples:Vector.<Number>, targetSamples:Vector.<Number>, newSize:int, sourceRate:int, targetRate:int = 44100):void {
// we need to expand the sample rate from whatever it is to targetRate Khz. This code
// is assuming that the sample rate will be < targetRate Khz.
var multiplier:Number = targetRate / sourceRate;
// convert the data
var measure:int = targetRate;
var sourceIndex:int = 0;
var targetIndex:int = 0;
while (targetIndex < newSize) {
if (measure >= sourceRate) {
var increment:Number = 0;
if (targetIndex > 0 && sourceIndex < sourceSamples.length - 1) {
increment = (sourceSamples[sourceIndex + 1] - sourceSamples[sourceIndex]) / multiplier;
}
targetSamples[targetIndex++] = sourceSamples[sourceIndex] + increment;
measure -= sourceRate;
} else {
sourceIndex++;
measure += targetRate;
}
}
}
}
}

View File

@@ -0,0 +1,126 @@
package org.as3wavsound.sazameki.format.wav.chunk {
import flash.utils.ByteArray;
import org.as3wavsound.sazameki.core.AudioSamples;
import org.as3wavsound.sazameki.core.AudioSetting;
import org.as3wavsound.sazameki.format.riff.Chunk;
/**
* ...
*
* @author Takaaki Yamazaki(zk design),
* @author Benny Bottema (modified, optimized and cleaned up code)
*/
public class WavdataChunk extends Chunk {
private var _samples:AudioSamples;
public function WavdataChunk() {
super('data');
}
public function setAudioData(samples:AudioSamples):void {
_samples = samples;
}
override protected function encodeData():ByteArray {
var bytes:ByteArray = new ByteArray();
bytes.endian = ENDIAN;
var setting:AudioSetting = _samples.setting;
var i:int;
var sig:Number;
var len:int = _samples.left.length;
var left:Vector.<Number>;
if (setting.channels == 2) {
left=_samples.left;
var right:Vector.<Number>=_samples.right;
if (setting.bitRate == 16) {
for (i = 0; i < len; i++) {
sig = left[i];
if (sig < -1) bytes.writeShort( -32767);
else if (sig > 1) bytes.writeShort( 32767);
else bytes.writeShort(sig * 32767);
sig = right[i];
if (sig < -1) bytes.writeShort(-32767);
else if (sig > 1) bytes.writeShort(32767);
else bytes.writeShort(sig * 32767);
}
} else {
for (i = 0; i < len; i++) {
sig = left[i];
if (sig<-1) bytes.writeByte(0);
else if (sig>1) bytes.writeByte(255);
else bytes.writeByte(sig*127+128);
sig = right[i];
if (sig<-1) bytes.writeByte(0);
else if (sig>1) bytes.writeByte(255);
else bytes.writeByte(sig*127+128);
}
}
} else {
left = _samples.left;
if (setting.bitRate == 16) {
for (i = 0; i < len; i++) {
sig = left[i];
if (sig < -1) bytes.writeShort(-32767);
else if (sig > 1) bytes.writeShort(32767);
else bytes.writeShort(sig * 32768);
}
} else {
for (i = 0; i < len; i++) {
sig = left[i];
if (sig<-1) bytes.writeByte(0);
else if (sig>1) bytes.writeByte(255);
else bytes.writeByte(sig*127+128);
}
}
}
return bytes;
}
public function decodeData(bytes:ByteArray, setting:AudioSetting):AudioSamples {
bytes.position = 0;
bytes.endian = ENDIAN;
var samples:AudioSamples = new AudioSamples(setting);
var length:int = bytes.length / (setting.bitRate / 8) / setting.channels;
var i:int;
var left:Vector.<Number>;
if (setting.channels == 2) {
left = samples.left;
var right:Vector.<Number> = samples.right;
if (setting.bitRate == 16) {
for (i = 0; i < length; ++i) {
left[i] = bytes.readShort() / 32767;
right[i] = bytes.readShort() / 32767;
}
} else {
for (i = 0; i < length; i++)
{
left[i] = bytes.readByte() / 255;
right[i] = bytes.readByte() / 255;
}
}
} else {
left = samples.left;
if (setting.bitRate == 16) {
for (i = 0; i < length; i++) {
left[i] = bytes.readShort() / 32767;
}
} else {
for (i = 0; i < length; i++) {
left[i] = bytes.readByte() / 255;
}
}
}
return samples;
}
}
}

View File

@@ -0,0 +1,56 @@
package org.as3wavsound.sazameki.format.wav.chunk {
import flash.utils.ByteArray;
import org.as3wavsound.sazameki.core.AudioSetting;
import org.as3wavsound.sazameki.format.riff.Chunk;
/**
* ...
*
* @author Takaaki Yamazaki(zk design),
* @author Benny Bottema (modified, optimized and cleaned up code)
*/
public class WavfmtChunk extends Chunk {
private var _setting:AudioSetting;
public function WavfmtChunk() {
super('fmt ');
}
public function setSetting(setting:AudioSetting):void {
_setting = setting;
}
override protected function encodeData():ByteArray {
var result:ByteArray = new ByteArray();
result.endian = ENDIAN;
//fmt ID(2)
result.writeShort(1);
//channels(2)
result.writeShort(_setting.channels);
//sampling rate(4)
result.writeInt(_setting.sampleRate);
//data rate(4)
result.writeInt(_setting.sampleRate * _setting.channels * (_setting.bitRate / 8));
//block size(2)
result.writeShort((_setting.bitRate / 8) * _setting.channels);
//bit rate(2)
result.writeShort(_setting.bitRate);
return result;
}
public function decodeData(bytes:ByteArray):AudioSetting {
bytes.position = 0;
bytes.endian = ENDIAN;
bytes.readShort();
var channels:int = bytes.readShort();
var smplRate:int = bytes.readInt();
bytes.readInt();
bytes.readShort();
var bit:int = bytes.readShort();
_setting = new AudioSetting(channels, smplRate, bit);
return _setting;
}
}
}

View File

@@ -0,0 +1,228 @@
/*
A fallback to flash for wav-output (for IE 10)
Please mind that wav data has to be copied to an ArrayBuffer object internally,
since we may not send binary data to the swf.
This may take some time and memory for longer utterances.
*/
var meSpeakFlashFallback = new function() {
var swfDefaultId='meSpeakFallback',
swfDefaultUrl='meSpeakFallback.swf',
swfElementId='', swfViaAX=false, swfInstalled=false, swfHasLoaded=false, swfVol=1;
// public
function swfInstallFallback(swfUrl, swfId, parentElementOrId) {
var parentEl, url;
if (swfInstalled) return true;
if (!swfIsAvailable(10)) return false;
swfInstalled=true;
// set defaults
swfElementId = (swfId && typeof swfId == 'string')? swfId:swfDefaultId;
url = (swfUrl && typeof swfUrl == 'string')? swfUrl:swfDefaultUrl;
if (parentElementOrId) {
if (typeof parentElementOrId == 'string') {
parentEl=document.getElementById(parentElementOrId);
}
else if (typeof parentElementOrId == 'object') {
parentEl=parentElementOrId=null;
}
}
if (!parentEl) parentEl=document.getElementsByTagName('body')[0];
if (!parentEl) return false;
// inject
var obj = swfCreate(
{
'data': url,
'width': '2',
'height': '2',
'id': swfElementId,
'name': swfElementId,
'align': 'top'
},
{
'quality': 'low',
'bgcolor': 'transparent',
'allowscriptaccess': 'sameDomain',
'allowfullscreen': 'false'
}
);
parentEl.appendChild(obj);
swfRegisterUnloadHandler();
return true;
}
function swfReady() {
return swfHasLoaded;
}
function swfSetVolume(v) {
if (wfHasLoaded) {
var obj=document.getElementById(swfElementId);
if (obj) el.setVolume(v);
}
swfVol=v;
}
function swfSpeak(txt, options) {
if (swfHasLoaded && window.meSpeak) {
var obj=document.getElementById(swfElementId);
if (obj) {
if (!typeof options != 'object') options={};
options.rawdata='array';
obj.play( meSpeak.speak(txt, options) );
}
}
}
function swf10Available() {
return swfIsAvailable(10);
}
function swfFallbackHandshake() {
swfHasLoaded=true;
if (swfVol!=1) swfSetVolume(swfVol);
if (window.console) console.log('meSpeak-SWF-fallback available.');
}
// private: a stripped-down version of swfobject.js
function swfIsAvailable(leastMajorVersion) {
// returns Boolean: flashplayer and version at least 10.x
var sf='Shockwave Flash', sfm='application/x-shockwave-flash';
if (navigator.plugins !== undefined && typeof navigator.plugins[sf] == 'object') {
var d=navigator.plugins[sf].description;
if (d && !(typeof navigator.mimeTypes !==undefined && navigator.mimeTypes[sfm] && !navigator.mimeTypes[sfm].enabledPlugin)) {
d=d.replace(/^.*\s+(\S+\s+\S+$)/, '$1');
if (leastMajorVersion<= parseInt(d.replace(/^(.*)\..*$/, '$1'), 10)) return true;
}
}
else if (window.ActiveXObject) {
try {
var a=new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
if (a) {
swfViaAX=true;
d=a.GetVariable('$version');
if (d) {
d=d.split(' ')[1].split(',');
if (leastMajorVersion<= parseInt(d[0], 10)) return true;
}
}
}
catch(e) {}
}
return false;
}
function swfCreate(attributes, params) {
if (swfViaAX) {
var att='', par='', i;
for (i in attributes) {
var a=i.toLowerCase;
if (a=='data') {
params.movie=attributes[i];
}
else if (a=='styleclass') {
att+=' class="'+attributes[i]+'"';
}
else if (a!='classid') {
att+=' '+i+'="'+attributes[i]+'"';
}
}
for (i in params) {
if (params[i] != Object.prototype[i]) par+=' <param name="'+i+'" value="'+params[i]+'" />';
}
var el=document.createElement('div');
el.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+att+'>'+par+'</object>';
return el;
}
else {
var o=document.createElement('object');
o.setAttribute('type', 'application/x-shockwave-flash');
for (var i in attributes) {
if (attributes[i] != Object.prototype[i]) {
var a=i.toLowerCase();
if (a=='styleclass') {
o.setAttribute('class', attributes[i]);
}
else if (a!='styleclass') {
o.setAttribute(i, attributes[i]);
}
}
}
for (i in params) {
if (attributes[i] != Object.prototype[i] && i.toLowerCase() != 'movie') {
var p=document.createElement('param');
p.setAttribute('name', i);
p.setAttribute('value', attributes[i]);
o.appendChild(p);
}
}
return o;
}
}
function swfRemove(obj) {
try {
if (typeof obj =='string') obj=document.getElementById(obj);
if (!obj || typeof obj !='object') return;
if (swfViaAX) {
obj.style.display='none';
swfRemoveObjectInIE(obj.id);
}
else if (obj.parentNode) {
obj.parentNode.removeChild(obj);
}
swfInstalled=false;
}
catch(e) {}
}
function swfRemoveObjectInIE(id) {
var obj=document.getElementById(obj);
if (obj) {
if (obj.readyState==4) {
for (var i in obj) {
if (typeof obj[i] =='function') obj[i] = null;
}
if (obj.parentNode) obj.parentNode.removeChild(obj);
}
else {
setTimeout(function() {swfRemoveObjectInIE(id)}, 10);
}
}
}
function swfUnloadHandler() {
if (swfElementId) swfRemove(swfElementId);
if (!window.addEventListener && window.detachEvent) window.detachEvent('onunload', swfUnloadHandler);
}
function swfRegisterUnloadHandler() {
if (window.addEventListener) {
window.addEventListener('unload', swfUnloadHandler, false);
}
else if (window.attachEvent) {
window.attachEvent('onunload', swfUnloadHandler);
}
}
return {
'install': swfInstallFallback,
'isAvailable': swf10Available,
'ready': swfReady,
'speak': swfSpeak,
'setVolume': swfSetVolume,
'swfFallbackHandshake': swfFallbackHandshake
}
};
function meSpeakFallbackHandshake() {
// handshake handler with swf external interface
meSpeakFlashFallback.swfFallbackHandshake();
}

View File

@@ -0,0 +1,168 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>meSpeak Flash Fallback</title>
<link href="http://fonts.googleapis.com/css?family=Open+Sans&amp;subset=latin" rel="stylesheet" type="text/css" />
<link href="http://fonts.googleapis.com/css?family=Lato:300&amp;subset=latin" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="../mespeak.js"></script>
<script type="text/javascript" src="flashFallback.js"></script>
<script type="text/javascript">
meSpeak.loadConfig("../mespeak_config.json");
meSpeak.loadVoice("../voices/en/en.json");
var fallbackInstalled = false;
var hasTypedArrays = Boolean(window.Int32Array && window.Float32Array
&& (window.Int32Array.prototype.subarray || window.Int32Array.subarray)
),
canSpeak = (hasTypedArrays && window.meSpeak && meSpeak.canPlay());
function checkAndInstall() {
// check typed array support (we need this) and wav-support (we fallback, if not present)
if (hasTypedArrays && window.meSpeak && !meSpeak.canPlay()) {
canSpeak = installFallback();
}
}
function installFallback() {
// install with explicit default values
// swf will be 2px x 2px (h x w), transparent
return fallbackInstalled = meSpeakFlashFallback.install(
'meSpeakFallback.swf', // url
'meSpeakFallback', // id of swf object
null // parent element to inject into
// (default: append to body)
);
}
function fallbackSpeak() {
meSpeakFlashFallback.speak('Hello world.', { 'speed': 180 } );
}
// some functions for abstracting
function speakAny( txt, options, vol ) {
if (fallbackInstalled) {
meSpeakFlashFallback.speak( txt, options );
}
else if (canSpeak) {
meSpeak.speak( txt, options, vol );
}
}
function setVolume( vol) {
if (fallbackInstalled) {
meSpeakFlashFallback.setVolume( vol );
}
else if (canSpeak) {
meSpeak.setVolume( vol );
}
}
function fallbackReady() {
// check if the swf has loaded and performed a handshake, indicating that it's available
return meSpeakFlashFallback.ready();
}
// install only, if needed
// if (document.addEventListener) document.addEventListener('DOMContentLoaded', checkAndInstall, false);
// install unconditionally (for testing purpose)
if (document.addEventListener) document.addEventListener('DOMContentLoaded', installFallback, false);
</script>
<style type="text/css">
html
{
margin: 0;
padding: 2em 1.5em 4.5em 1.5em;
background-color: #e2e3e4;
}
body
{
max-width: 900px;
padding: 2px 40px 60px 40px;
margin: 0 auto 0 auto;
background-color: #fafafb;
color: #111;
font-family: 'Open Sans',sans-serif;
font-size: 13px;
line-height: 19px;
}
h1,h2,h3,h4
{
font-family: 'Lato',sans-serif;
font-weight: 300;
}
h1 {
font-size: 46px;
line-height: 46px;
color: #2681a7;
margin-top: 0.5em;
margin-bottom: 0.5em;
padding: 0;
}
h2
{
font-size: 36px;
color: #111;
margin-top: 0;
margin-bottom: 1.5em;
clear: both;
}
h1 span.pict { font-size: 38px; color: #ccc; margin-left: 0.5em; letter-spacing: -2px; }
p.codesample,xmp
{
margin: 1em 0;
padding: 1em 0 1em 2em;
white-space: pre;
font-family: monospace;
line-height: 18px;
background-color: #f2f3f5;
color: #111;
}
a { color: #006f9e; }
a:hover,a:focus { color: #2681a7; }
a:active { color: #cd360e; }
</style>
</head>
<body>
<h1>meSpeak.js <span class="pict">(( &bull; ))</span></h1>
<h2>Flash Fallback <small>(for IE 10)</small></h2>
<p>A fallback to play meSpeak's wav-files via Flash.<br />Since typed arrays are still a requirement, the only use-case is MS Internet Explorer 10.<br />
Please note that, since we may not send binary data to a swf-object, the data has to be copied internally to a binary object, which may take some time and memory.<br />Because of this, the status of this solution is at best &quot;experimental&quot; and not for everyday use.</p>
<p>The fallback &quot;meSpeakFallback.swf&quot; uses the <a href="http://code.google.com/p/as3wavsound/">AS3WavSound</a> library (v0.9) for wav-playback inside the SWF. (Ironically Flash doesn't support native wav-playback either.)<br />The swf-file is compiled for network use, meaning it will work only, if loaded over a network (web-server).</p>
<p>For testing, the fallback is installed for all browsers on this page:
<input type="button" value="speak: Hello world." onclick="fallbackSpeak();" /></p>
<p>See page source for API &amp; details.</p>
<p>Download: <a href="http://www.masswerk.at/mespeak/msie_flashFallback.zip">msie_flashFallback.zip</a><br />
<em>(Installation: Put the unzipped directory inside your mespeak-directory.)</em></p>
<hr style="margin-top: 2em; margin-bottom: 2em;">
<p><strong>A Note on Usage:</strong><br />While the fallback-script strips down the coded needed to inject a swf-object to a minimum, best practice would be to include the script only, if applicable (i.e.: for MS IE 10 only), using MS-specific conditional comments:</p>
<xmp style="margin-left: 1em;">
<!--[if IE 10]>
<script type="text/javascript" src="flashFallback.js"></script>
<![endif]-->
</xmp>
<p>If doing so, you would have to check for the existence of <code>meSpeakFlashFallback</code> first, before calling it:</p>
<xmp style="margin-left: 1em;">
if (window.meSpeakFlashFallback) callbackInstalled = meSpeakFlashFallback.install();
// later, see page source for API details and usage
if (callbackInstalled) meSpeakFlashFallback.speak('Hello world.');
</xmp>
<p>This way, page- and memory-loads are reduced to a minimum for all browsers.</p>
<p>Please note that there is a delay between calling <code>install()</code> and the fallback actually being available, since the swf-file has to load and initialize first.</p>
<p>&nbsp;</p>
<p>Norbert Landsteiner, mass:werk &ndash; media environments, <a href="http://www.masswerk.at/" target="_top">www.masswerk.at</a><br />
Vienna, July 2013</p>
</body>
</html>

Binary file not shown.

BIN
tools/speaker/voices/.DS_Store vendored Executable file

Binary file not shown.

6
tools/speaker/voices/ca.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/cs.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/de.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/el.json Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/eo.json Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/es.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/fi.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/fr.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/hu.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/it.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/kn.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/la.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/lv.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/nl.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/pl.json Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/pt.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/ro.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/sk.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/sv.json Executable file

File diff suppressed because one or more lines are too long

6
tools/speaker/voices/tr.json Executable file

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More