There is a function in PHP GD for Linear Dodge?
I wrote this function but I would like to know if exists a function like this in PHP GD
function imagecopyAdd (&$dst_im, &$src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h)
{
for($i = 0; $i < $src_w; $i++)
{
for($c = 0; $c < $src_h; $c++)
{
$rgb1 = imagecolorat($dst_im, ($i+$dst_x), ($c+$dst_y));
$colors1 = imagecolorsforindex($dst_im, $rgb1);
$rgb2 = imagecolorat($src_im, ($i+$src_x), ($c+$src_y));
$colors2 = imagecolorsforindex($src_im, $rgb2);
$r = $colors1["red"]+$colors2["red"];
if($r > 255)
$r = 255;
$g = $colors1["green"]+$colors2["green"];
if($g > 255)
$g = 255;
$b = $colors1["blue"]+$colors2["blue"];
if($b > 255)
$b = 255;
$color = imagecolorallocate($dst_im, $r, $g, $b);
imagesetpixel($dst_im, ($i+$dst_x), ($c+$dst_y), $color);
}
}
}
While my understanding of image manipulation at more than a visual level is fundamental at best, it seems like this may be built in to the options for imagefilter.
See this comment for the users' custom implementation that he says performs the exact same function as the built in option:
It turns out PHP's Colorize is the equivalent of Photoshop's "Linear Dodge" layer filter.
Note these lines in his comment:
// Usage: Just as imagefilter(), except with no filtertype.
// imagefilterhue(resource $image, int $red, int $green , int $blue)
imagefilterhue($im,2,70,188);
// The equivalent with colorize, as tested in demo image:
imagefilter($im, IMG_FILTER_COLORIZE, 2, 70, 188);
Where imagefilterhue is his custom implementation and imagefilter is the PHP GD function.
Related
I was playing around with parallel sorting tonight.
creating sort file
naive-sort ...
1000000
23.61265496
partial-hyper-sort ...
4
7.4924575
simple-hyper-sort ...
1000000
141.7945921
naive-hyper-sort ...
1000000
23.5756172
Two things stand out.
a) naive-hyper-sort is just as fast as ordinary sort
b) The sorting in partial-hyper-sort is 66% faster than ordinary sort.
My problem: partial-hyper-sort is exactly that: "partial". It returns (on my system) 4 sublists, but you want of course one. My attempt to merge them into one (simple-hyper-sort) is an order of magnitude slower than the whole sorting!
So how do I get this faster? And if someone can explain why naive-hyper-sort is not faster than naive-sort, bonus points and a cookie (seriously, a literal cookie).
create-sortfile
unless "tosort.txt".IO.e;
my $start = DateTime.now;
say "naive-sort ...";
say naive-sort.elems;
say DateTime.now - $start;
$start = DateTime.now;
say "partial-hyper-sort ...";
say partial-hyper-sort.elems;
say DateTime.now - $start;
$start = DateTime.now;
say "simple-hyper-sort ...";
say simple-hyper-sort.elems;
say DateTime.now - $start;
$start = DateTime.now;
say "naive-hyper-sort ...";
say naive-hyper-sort.elems;
say DateTime.now - $start;
sub create-sortfile
{
say "creating sort file";
my $to-sort = "tosort.txt".IO.open(:w);
$to-sort.say( ( 10_000 .. 99_999 ).pick )
for ( 1 .. 1_000_000 );
$to-sort.close;
}
sub simple-hyper-sort
{
my $to-sort = "tosort.txt".IO.open( :r );
my $lines = $to-sort.lines;
my $degrees = $*KERNEL.cpu-cores;
my $batch = $lines.elems div $degrees;
my #parts = $lines.batch( $batch ).hyper( :batch(1) ).map({ .sort });
my #index = 0 xx $degrees;
return gather loop
{
my $smallest = Inf;
my $smallest-index = -1;
my $smallest-degree = -1;
for ^$degrees -> $degree
{
my $index = #index[$degree];
if ( $index < $batch )
{
my $value = #parts[$degree;$index];
if $value < $smallest
{
$smallest = $value;
$smallest-index = $index;
$smallest-degree = $degree;
}
}
}
last if $smallest-index < 0;
#index[$smallest-degree]++;
take $smallest;
}
}
sub partial-hyper-sort
{
my $to-sort = "tosort.txt".IO.open( :r );
my $lines = $to-sort.lines;
my $degrees = $*KERNEL.cpu-cores;
my $batch = $lines.elems div $degrees;
my #parts = $lines.batch( $batch ).hyper( :batch(1) ).map({ .sort });
}
multi sub naive-hyper-sort
{
my $to-sort = "tosort.txt".IO.open( :r );
my $lines = $to-sort.lines;
my $degrees = $*KERNEL.cpu-cores;
my $batch = $lines.elems div $degrees;
$lines.hyper( :$batch, :$degrees ).sort;
}
sub naive-sort {
my $to-sort = "tosort.txt".IO.open( :r );
$to-sort.lines.sort;
}
Using .hyper and .race only results in a speedup if there is a parallel implementation of the operation that follows. At the time of writing, there is not a parallel sort implementation in Rakudo, which means that it will fall back to using the regular sort implementation. So, this answers why native-hyper-sort doesn't come out faster right now (however it almost certainly will in the future).
The idea in simple-hyper-sort is along the right lines: break the data up into sublists, sort the sublists, and then merge them. We can therefore parallelize the sorting of the sublists. As you've observed, this achieving a win is dependent on the merge operation itself being fast enough, and so we'd need to carefully optimize that.
It's much easier to write a tight (not to mention correct!) merge operation if it only needs to merge two sublists. Thus, we need to structure the problem in a way that gives us that. This points to a different approach:
Break the list in half
start a task to sort each half
await the two tasks
Merge the results of the two tasks
Note that step 2 involves recursion. We stop recursing when the size of a partition is too small, and use the built-in sort on such partitions. (We can choose to define "too small" by dividing the input list size by the number of CPU cores, along the lines of your example.)
Thus we get a solution like this:
sub parallel-merge-sort {
my $to-sort = "tosort.txt".IO.open( :r );
my $lines = $to-sort.lines;
return do-sort $lines, ceiling($lines.elems / $*KERNEL.cpu-cores);
sub do-sort(#in, $limit) {
if #in.elems < $limit {
#in.sort
}
else {
my $pivot = #in.elems div 2;
merge |await
(start do-sort #in[0..$pivot], $limit),
(start do-sort #in[$pivot^..#in.end], $limit)
}
}
sub merge(#a, #b) {
my #result;
my int $a-idx = 0;
my int $a-elems = +#a;
my int $b-idx = 0;
my int $b-elems = +#b;
my int $r-idx = 0;
while $a-idx < $a-elems && $b-idx < $b-elems {
my $a := #a[$a-idx];
my $b := #b[$b-idx];
if $a before $b {
$a-idx++;
#result[$r-idx++] := $a;
}
else {
$b-idx++;
#result[$r-idx++] := $b;
}
}
if $a-idx < $a-elems {
#result[$r-idx++] := $_ for #a[$a-idx..*];
}
elsif $b-idx < $b-elems {
#result[$r-idx++] := $_ for #b[$b-idx..*];
}
return #result;
}
}
I didn't spend terribly long optimizing this (haven't profiled, etc.), but did take care to use natives and binding in order to reduce allocations. On My Machine, this does give a speedup over the serial sorting, however.
One other easy speedup we can get on this - at the cost of a tad more complexity in the code - comes from realizing that we don't need to slice the input in do-sort until the point that we actually need to send it to the built-in sort:
sub do-sort(#in, $limit, $from = 0, $to = #in.end) {
my $elems = $to - $from;
if $elems < $limit {
#in[$from..$to].sort
}
else {
my $pivot = $from + $elems div 2;
merge |await
(start do-sort #in, $limit, $from, $pivot),
(start do-sort #in, $limit, $pivot + 1, $to)
}
}
Which saves some work; by this point, I measure a factor of two speedup on the machine I'm testing it on, which isn't amazing, but given we've an enforced serial O(n) step, and a bunch more parallelized O(n) steps, over the serial sort algorithm, it's perhaps not so disappointing after all.
Last week I decided to give a try to Perl6 and started to reimplement one of my program.
I have to say, Perl6 is so the easy for object programming, an aspect very painfull to me in Perl5.
My program have to read and store big files, such as whole genomes (up to 3 Gb and more, See example 1 below) or tabulate data.
The first version of the code was made in the Perl5 way by iterating line by line ("genome.fa".IO.lines). It was very slow and unsable for a correct execution time.
my class fasta {
has Str $.file is required;
has %!seq;
submethod TWEAK() {
my $id;
my $s;
for $!file.IO.lines -> $line {
if $line ~~ /^\>/ {
say $id;
if $id.defined {
%!seq{$id} = sequence.new(id => $id, seq => $s);
}
my $l = $line;
$l ~~ s:g/^\>//;
$id = $l;
$s = "";
}
else {
$s ~= $line;
}
}
%!seq{$id} = sequence.new(id => $id, seq => $s);
}
}
sub MAIN()
{
my $f = fasta.new(file => "genome.fa");
}
So after a little bit of RTFM, I changed for a slurp on the file, a split on the \n which I parsed with a for loop. This way I managed to load the data in 2 min. Much better but not enough. By cheating, I mean by removing a maximum of \n (Example 2), I decreased the execution time to 30 seconds. Quite good, but not totaly satisfied, by this fasta format is not the most used.
my class fasta {
has Str $.file is required;
has %!seq;
submethod TWEAK() {
my $id;
my $s;
say "Slurping ...";
my $f = $!file.IO.slurp;
say "Spliting file ...";
my #lines = $f.split(/\n/);
say "Parsing lines ...";
for #lines -> $line {
if $line !~~ /^\>/ {
$s ~= $line;
}
else {
say $id;
if $id.defined {
%!seq{$id} = seq.new(id => $id, seq => $s);
}
$id = $line;
$id ~~ s:g/^\>//;
$s = "";
}
}
%!seq{$id} = seq.new(id => $id, seq => $s);
}
}
sub MAIN()
{
my $f = fasta.new(file => "genome.fa");
}
So RTFM again and I discovered the magic of Grammar. So new version and an execution time of 45 seconds whatever the fasta format used. Not the fastest way but more elegant and stable.
my grammar fastaGrammar {
token TOP { <fasta>+ }
token fasta {<.ws><header><seq> }
token header { <sup><id>\n }
token sup { '>' }
token id { <[\d\w]>+ }
token seq { [<[ACGTNacgtn]>+\n]+ }
}
my class fastaActions {
method TOP ($/){
my #seqArray;
for $<fasta> -> $f {
#seqArray.push: seq.new(id => $f.<header><id>.made, seq => $f<seq>.made);
}
make #seqArray;
}
method fasta ($/) { make ~$/; }
method id ($/) { make ~$/; }
method seq ($/) { make $/.subst("\n", "", :g); }
}
my class fasta {
has Str $.file is required;
has %seq;
submethod TWEAK() {
say "=> Slurping ...";
my $f = $!file.IO.slurp;
say "=> Grammaring ...";
my #seqArray = fastaGrammar.parse($f, actions => fastaActions).made;
say "=> Storing data ...";
for #seqArray -> $s {
%!seq{$s.id} = $s;
}
}
}
sub MAIN()
{
my $f = fasta.new(file => "genome.fa");
}
I think that I found good solution to handle these kind of big files, but performances are still under those of Perl5.
As a newbie in Perl6, I would be interested to know if there is better ways to deal with big data or if there is some limitation due to the Perl6 implementation ?
As a newbie in Perl6, I would ask two questions :
Is there other Perl6 mechanisms that I'm not aware yet, or not yet
documented, for storing huge data from a file (like my genomes) ?
Did I reach the maximum performances for the current version of
Perl6 ?
Thanks for reading !
Fasta Example 1 :
>2L
CGACAATGCACGACAGAGGAAGCAGAACAGATATTTAGATTGCCTCTCATTTTCTCTCCCATATTATAGGGAGAAATATG
ATCGCGTATGCGAGAGTAGTGCCAACATATTGTGCTCTTTGATTTTTTGGCAACCCAAAATGGTGGCGGATGAACGAGAT
...
>3R
CGACAATGCACGACAGAGGAAGCAGAACAGATATTTAGATTGCCTCTCATTTTCTCTCCCATATTATAGGGAGAAATATG
ATCGCGTATGCGAGAGTAGTGCCAACATATTGTGCTCTTTGATTTTTTGGCAACCCAAAATGGTGGCGGATGAACGAGAT
...
Fasta example 2 :
>2L
GACAATGCACGACAGAGGAAGCAGAACAGATATTTAGATTGCCTCTCAT...
>3R
TAGGGAGAAATATGATCGCGTATGCGAGAGTAGTGCCAACATATTGTGCT...
EDIT
I applied advises of #Christoph and #timotimo and test with code:
my class fasta {
has Str $.file is required;
has %!seq;
submethod TWEAK() {
say "=> Slurping / Parsing / Storing ...";
%!seq = slurp($!file, :enc<latin1>).split('>').skip(1).map: {
.head => seq.new(id => .head, seq => .skip(1).join) given .split("\n").cache;
}
}
}
sub MAIN()
{
my $f = fasta.new(file => "genome.fa");
}
The program finished in 2.7s, which is so great !
I also tried this code on the wheat genome (10 Gb). It finished in 35.2s.
Perl6 is not so slow finally !
Big Thank for the help !
One simple improvement is to use a fixed-width encoding such as latin1 to speed up character decoding, though I'm not sure how much this will help.
As far as Rakudo's regex/grammar engine is concerned, I've found it to be pretty slow, so it might indeed be necessary to take a more low-level approach.
I did not do any benchmarking, but what I'd try first is something like this:
my %seqs = slurp('genome.fa', :enc<latin1>).split('>')[1..*].map: {
.[0] => .[1..*].join given .split("\n");
}
As the Perl6 standard library is implemented in Perl6 itself, it is sometimes possible to improve performance by just avoiding it, writing code in an imperative style such as this:
my %seqs;
my $data = slurp('genome.fa', :enc<latin1>);
my $pos = 0;
loop {
$pos = $data.index('>', $pos) // last;
my $ks = $pos + 1;
my $ke = $data.index("\n", $ks);
my $ss = $ke + 1;
my $se = $data.index('>', $ss) // $data.chars;
my #lines;
$pos = $ss;
while $pos < $se {
my $end = $data.index("\n", $pos);
#lines.push($data.substr($pos..^$end));
$pos = $end + 1
}
%seqs{$data.substr($ks..^$ke)} = #lines.join;
}
However, if the parts of the standard library used has seen some performance work, this might actually make things worse. In that case, the next step to take would be adding low-level type annotations such as str and int and replacing calls to routines such as .index with NQP builtins such as nqp::index.
If that's still too slow, you're out of luck and will need to switch languages, eg calling into Perl5 by using Inline::Perl5 or C using NativeCall.
Note that #timotimo has done some performance measurements and wrote an article about it.
If my short version is the baseline, the imperative version improves performance by 2.4x.
He actually managed to squeeze a 3x improvement out of the short version by rewriting it to
my %seqs = slurp('genome.fa', :enc<latin-1>).split('>').skip(1).map: {
.head => .skip(1).join given .split("\n").cache;
}
Finally, rewriting the imperative version using NQP builtins sped things up by a factor of 17x, but given potential portability issues, writing such code is generally discouraged, but may be necessary for now if you really need that level of performance:
use nqp;
my Mu $seqs := nqp::hash();
my str $data = slurp('genome.fa', :enc<latin1>);
my int $pos = 0;
my str #lines;
loop {
$pos = nqp::index($data, '>', $pos);
last if $pos < 0;
my int $ks = $pos + 1;
my int $ke = nqp::index($data, "\n", $ks);
my int $ss = $ke + 1;
my int $se = nqp::index($data ,'>', $ss);
if $se < 0 {
$se = nqp::chars($data);
}
$pos = $ss;
my int $end;
while $pos < $se {
$end = nqp::index($data, "\n", $pos);
nqp::push_s(#lines, nqp::substr($data, $pos, $end - $pos));
$pos = $end + 1
}
nqp::bindkey($seqs, nqp::substr($data, $ks, $ke - $ks), nqp::join("", #lines));
nqp::setelems(#lines, 0);
}
I have an image and rotate it with both MS Paint and GDI. I want to show that the rotated image from both methods are the same.
Here is the code I have to rotate image with GDI
#include <GDIPlus.au3>
_GDIPlus_Startup()
$hImage1 = _GDIPlus_ImageLoadFromFile(#ScriptDir & "\Picture.gif")
$hGraphic1 = _GDIPlus_ImageGetGraphicsContext($hImage1)
$hImage2 = _GDIPlus_BitmapCreateFromGraphics(_GDIPlus_ImageGetWidth($hImage1), _GDIPlus_ImageGetHeight($hImage1), $hGraphic1)
$hGraphic2 = _GDIPlus_ImageGetGraphicsContext($hImage2)
$matrix = _GDIPlus_MatrixCreate()
_GDIPlus_MatrixRotate($matrix,90)
_GDIPlus_GraphicsSetTransform($hGraphic2, $matrix)
_GDIPlus_GraphicsDrawImage($hGraphic2, $hImage1, 0, -590)
_GDIPlus_ImageSaveToFile($hImage2, #ScriptDir & "\out.gif")
_GDIPlus_MatrixDispose($matrix)
_GDIPlus_GraphicsDispose($hGraphic1)
_GDIPlus_GraphicsDispose($hGraphic2)
_GDIPlus_ImageDispose($hImage1)
_GDIPlus_ImageDispose($hImage2)
_GDIPlus_ShutDown ()
Then I used this code to compare 2 images:
$bm1 = _GDIPlus_ImageLoadFromFile(#ScriptDir & "\Picture1.gif")
$bm2 = _GDIPlus_ImageLoadFromFile(#ScriptDir & "\out.gif")
if ComparePicture($bm1, $bm2) == True Then
MsgBox(0, "Test result", "Same image!")
Else
MsgBox(0, "Test result", "Different image!")
EndIf
_GDIPlus_ImageDispose($bm1)
_GDIPlus_ImageDispose($bm2)
_GDIPlus_Shutdown()
Func ComparePicture($bm1, $bm2)
$Bm1W = _GDIPlus_ImageGetWidth($bm1)
$Bm1H = _GDIPlus_ImageGetHeight($bm1)
$BitmapData1 = _GDIPlus_BitmapLockBits($bm1, 0, 0, $Bm1W, $Bm1H, $GDIP_ILMREAD, $GDIP_PXF08INDEXED )
$Stride = DllStructGetData($BitmapData1, "Stride")
$Scan0 = DllStructGetData($BitmapData1, "Scan0")
$ptr1 = $Scan0
$size1 = ($Bm1H - 1) * $Stride + ($Bm1W - 1) * 4
$Bm2W = _GDIPlus_ImageGetWidth($bm2)
$Bm2H = _GDIPlus_ImageGetHeight($bm2)
$BitmapData2 = _GDIPlus_BitmapLockBits($bm2, 0, 0, $Bm2W, $Bm2H, $GDIP_ILMREAD, $GDIP_PXF08INDEXED)
$Stride = DllStructGetData($BitmapData2, "Stride")
$Scan0 = DllStructGetData($BitmapData2, "Scan0")
$ptr2 = $Scan0
$size2 = ($Bm2H - 1) * $Stride + ($Bm2W - 1) * 4
$smallest = $size1
If $size2 < $smallest Then $smallest = $size2
$call = DllCall("msvcrt.dll", "int:cdecl", "memcmp", "ptr", $ptr1, "ptr", $ptr2, "int", $smallest)
_GDIPlus_BitmapUnlockBits($bm1, $BitmapData1)
_GDIPlus_BitmapUnlockBits($bm2, $BitmapData2)
Return ($call[0]=0)
EndFunc
I tried changing the file type, color depth, etc. but I could not get the code to show that they are the same. When I do not rotate the picture i.e
_GDIPlus_MatrixRotate($matrix,0)
then it recognize the same image. When I rotate right 90, it doesn't. Does anyone knows what might be going on?
Thanks
For reference, this question has also been asked on the AutoIt forums here.
I think $GDIP_PXF08INDEXED is modifying the images differently. Try it without setting it and it should work.
Furthermore, you can use this code to flip the image:
$hImage1 = _GDIPlus_ImageLoadFromFile(#ScriptDir & "\Picture1.gif")
_GDIPlus_ImageRotateFlip($hImage1, 1) ;90°
_GDIPlus_ImageSaveToFile($hImage1, #ScriptDir & "\out.gif")
_GDIPlus_ImageDispose($hImage1)
Br,
UEZ
I am creating a Mozilla Firefox toolbar to show PageRank and Alexa ranking of current website. One way I came to know is to use XMLHttpRequest in my JavaScript file to get information from a PHP page hosted on my website's server.
The PHP class has this function:
function check($page) {
// Open a socket to the toolbarqueries address, used by Google Toolbar
$socket = fsockopen("toolbarqueries.google.com", 80, $errno, $errstr, 30);
// If a connection can be established
if($socket) {
// Prep socket headers
$out = "GET /tbr?client=navclient-auto&ch=".$this->checkHash($this->createHash($page)).
"&features=Rank&q=info:".$page."&num=100&filter=0 HTTP/1.1\r\n";
$out .= "Host: toolbarqueries.google.com\r\n";
$out .= "User-Agent: Mozilla/4.0 (compatible; GoogleToolbar 2.0.114-big; Windows XP 5.1)\r\n";
$out .= "Connection: Close\r\n\r\n";
// Write settings to the socket
fwrite($socket, $out);
// When a response is received...
$result = "";
while(!feof($socket)) {
$data = fgets($socket, 128);
$pos = strpos($data, "Rank_");
if($pos !== false){
$pagerank = substr($data, $pos + 9);
$result += $pagerank;
}
}
// Close the connection
fclose($socket);
// Return the rank!
return $result;
}
Is there a better way to get page ranks in my custom Firefox toolbar without having to host a PHP service?
// Create a url hash
function createHash($string) {
$check1 = $this->stringToNumber($string, 0x1505, 0x21);
$check2 = $this->stringToNumber($string, 0, 0x1003F);
$factor = 4;
$halfFactor = $factor/2;
$check1 >>= $halfFactor;
$check1 = (($check1 >> $factor) & 0x3FFFFC0 ) | ($check1 & 0x3F);
$check1 = (($check1 >> $factor) & 0x3FFC00 ) | ($check1 & 0x3FF);
$check1 = (($check1 >> $factor) & 0x3C000 ) | ($check1 & 0x3FFF);
$calc1 = (((($check1 & 0x3C0) << $factor) | ($check1 & 0x3C)) << $halfFactor ) | ($check2 & 0xF0F );
$calc2 = (((($check1 & 0xFFFFC000) << $factor) | ($check1 & 0x3C00)) << 0xA) | ($check2 & 0xF0F0000 );
return ($calc1 | $calc2);
}
// Create checksum for hash
function checkHash($hashNumber)
{
$check = 0;
$flag = 0;
$hashString = sprintf('%u', $hashNumber) ;
$length = strlen($hashString);
for ($i = $length - 1; $i >= 0; $i --) {
$r = $hashString{$i};
if(1 === ($flag % 2)) {
$r += $r;
$r = (int)($r / 10) + ($r % 10);
}
$check += $r;
$flag ++;
}
$check %= 10;
if(0 !== $check) {
$check = 10 - $check;
if(1 === ($flag % 2) ) {
if(1 === ($check % 2)) {
$check += 9;
}
$check >>= 1;
}
}
return '7'.$check.$hashString;
}
If your PHP code only makes an HTTP request then you can just do the same request from the Firefox extension as well:
var request = new XMLHttpHeader();
request.open("http://toolbarqueries.google.com/tbr?client=navclient-auto&ch=...");
request.setRequestHeader("User-Agent", "Mozilla/4.0 (compatible; GoogleToolbar 2.0.114-big; Windows XP 5.1)");
request.send();
However, you should clarify whether this use of a Google server (particularly masquerading as Google Toolbar) complies with their Terms of Service. Otherwise you might find yourself confronted with legal action or at the very least sudden changes in the way this web service works.
As to the hash function: obviously you can either translate this algorithm to JavaScript (which is pretty straightforward from the look of it) or search around to see whether anybody did it already. E.g. I found this JS-based hash algorithm implementation (it's a different algorithm that is prefixed with 8 instead of 7 however, note also that this prefix isn't returned by the hash function but is rather part of the URL there).
How to write this without goto:
ob_start();
$a = 0;
echo "START of LEFT<br />";
begin:
if($a > 0) {
echo "CONTENT LEFT: $a<BR />";
<VERY DIFFICULT ALGORHITM>
goto end;
}
<... ALL THE REST CODE OF LEFT ...>
echo "END of LEFT<br /><br />";
$output1 = ob_get_contents();
ob_end_clean();
ob_start();
echo "START of CENTER<br />";
$a = 5; goto begin;
end:
<... ALL THE REST CODE OF CENTER ...>
echo "END of CENTER<br />";
$output2 = ob_get_contents();
ob_end_clean();
// print it
echo $output1.$output2;
To get this echo:
START of LEFT
CONTENT LEFT: 5
END of LEFT
START of CENTER
END of CENTER
Requirements:
1. I'm not allowed to change the order(CORE( echo $a ), and PLUGIN( $a=5 )):
ob_start();
$a = 0;
<ANY CODE>
echo $a;
$output1 = ob_get_contents();
ob_end_clean();
ob_start();
<ANY CODE>
$a = rand(0,10);
$output2 = ob_get_contents();
ob_end_clean();
2. Output must be generated via ob_get_contents();
But I'm allowed to write ANY CODE in places.
// Solvings
ob_get_contents(); Helps only if want to replace few lines in output HTML CODE, but can't change a value of variable, to change the ALGORHYTM(depends of var value), which generates the random HTML code.
Also,
As I checked my code, I understand, that my code, even with GOTO labels statement , DOES NOT going to change the $output1 content ?. How to do that? Is the only way is to recache the $output1 from his beggining. Or maybe I'm able to do this in other ways?
You are familiar with the concept of methods/functions? If not ( and it seems that chances are.. ) you should really learn something about those first. It's then a piece of cake to split functionality out of a monolithic block of code to small, maintainable pieces of code.
Structured programming - http://php.net/manual/en/language.oop5.php
If i understood well what you want to do I would use recursive functions instead of goto. for example look at this math expression parser i've witten in C some time ago:
#include <cstdio>
const long MAX = 100010;
char S[MAX], *p=S;
long eval();
long termen();
long factor();
int main() {
FILE *fin=fopen("evaluare.in", "r");
FILE *fout=fopen("evaluare.out", "w");
fgets(S, MAX, fin);
fprintf(fout, "%ld\n", eval());
return 0;
}
long eval() {
long r = termen();
while ( *p=='+' || *p=='-' ) {
switch ( *p ) {
case '+':
++p; // go over "+"
r += termen();
break;
case '-':
++p; // go over "-"
r -= termen();
break;
}
}
return r;
}
long termen() {
long r = factor();
while ( *p=='*' || *p=='/' ) {
switch ( *p ) {
case '*' :
++p;
r *= factor();
break;
case '/':
++p;
r /= factor();
break;
}
}
return r;
}
long factor() {
long r=0;
if ( *p == '(' ) { // subexpression
++p; // go over '('
r = eval();
++p; // go over ')'
} else {
while ( *p>='0' && *p<='9' ) { // number
r = r*10 + *p - '0';
++p;
}
}
return r;
}
The main idea is to split the code in functions and where you have let's say:
goto apocalypse
you'll have:
Apocalypse();
That's the long story said short.