问:
Angular + Firebase: how to store/retrieve objects with list properties?
chatroom.service.ts:

```<code>...
export class Message {
  author: string;
  body: string;
}

export class Chatroom {
  title: string;
  messages: Message[];  // <-- seems to be the problem
}

@Injectable()
export class ChatroomService {
  ...
  getChatroom = (chatroomId: string): FirebaseObjectObservable<Chatroom> =>
    this.db.object('/chatrooms/' + chatroomId);
  ...
</code>```

chatroom.component.ts:

```<code>...
export class ChatroomComponent implements OnInit {
  chatroom: Chatroom;

  private sub: any;

  ngOnInit() {
    this.sub = this.route.params
      .subscribe(params => {
        this.sub = this.chatroomService.getChatroom(params['chatroomId'])
          .subscribe(chatroom => this.chatroom = chatroom);
      });
  }
  ...
</code>```

chatroom.component.html

```<code><div *ngIf="chatroom">
  <p *ngFor="let message of chatroom.messages">{{message.author}}: {{message.body}}</p>
</div>
</code>```

error:

```<code>Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.
</code>```

The problem is that the Chatroom object's "message" property is treated by Firebase as an object and whereas I want it to be treated an ngFor-iterable list. Any suggestions on how to make this work?

EDIT: Here is the Firebase data structure:

```<code>{
  "chatrooms" : {
    "chatroom_342768235" : {
      "title" : "a chatroom",
      "messages" : {
        "message_3252253" : {
          "author" : "Joe",
          "body" : "test message"
        },
        "message_2653837" : {
          "author" : "Kim",
          "body" : "another message"
        }
      }
    },
    "chatroom_426482763" : {
      "title" : "another chatroom",
      "messages" : {
        "message_1243525" : {
          "author" : "Tom",
          "body" : "blah blah"
        }
      }
    }
  }
}
</code>```

答:
If possible add a setter/getter methods tomessages property in Chatroom class.

Declare messages property as typed array.

```<code>export class Chatroom {
  title: string;
  private _messages : {[key: string]: Message[]};

  public set messages(value: {[key: string]: Message[]}) {
        this._messages = {};
        for (let msg in value) {
               this._messages[msg] = value[msg];
        }
  }

  public get messages(): {[key: string]: Message[]} {
    return this._messages;
  }

}
</code>```

With this approach messages property is a proper array with string index and should be iterable now. Only reason for using typed array is you can access the name of messages message_2653837 and message_3252253.

Body:
chatroom.service.ts:

...
export class Message {
  author: string;
  body: string;
}

export class Chatroom {
  title: string;
  messages: Message[];  // <-- seems to be the problem
}

@Injectable()
export class ChatroomService {
  ...
  getChatroom = (chatroomId: string): FirebaseObjectObservable<Chatroom> =>
    this.db.object('/chatrooms/' + chatroomId);
  ...

chatroom.component.ts:

...
export class ChatroomComponent implements OnInit {
  chatroom: Chatroom;

  private sub: any;

  ngOnInit() {
    this.sub = this.route.params
      .subscribe(params => {
        this.sub = this.chatroomService.getChatroom(params['chatroomId'])
          .subscribe(chatroom => this.chatroom = chatroom);
      });
  }
  ...

chatroom.component.html

{{message.author}}: {{message.body}}

error:

Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.

The problem is that the Chatroom object's "message" property is treated by Firebase as an object and whereas I want it to be treated an ngFor-iterable list. Any suggestions on how to make this work?

EDIT: Here is the Firebase data structure:

{
  "chatrooms" : {
    "chatroom_342768235" : {
      "title" : "a chatroom",
      "messages" : {
        "message_3252253" : {
          "author" : "Joe",
          "body" : "test message"
        },
        "message_2653837" : {
          "author" : "Kim",
          "body" : "another message"
        }
      }
    },
    "chatroom_426482763" : {
      "title" : "another chatroom",
      "messages" : {
        "message_1243525" : {
          "author" : "Tom",
          "body" : "blah blah"
        }
      }
    }
  }
}

Body:
If possible add a setter/getter methods tomessages property in Chatroom class.

Declare messages property as typed array.

export class Chatroom {
  title: string;
  private _messages : {[key: string]: Message[]};

  public set messages(value: {[key: string]: Message[]}) {
        this._messages = {};
        for (let msg in value) {
               this._messages[msg] = value[msg];
        }
  }

  public get messages(): {[key: string]: Message[]} {
    return this._messages;
  }

}

With this approach messages property is a proper array with string index and should be iterable now. Only reason for using typed array is you can access the name of messages message_2653837 and message_3252253.


来源: stackexchange

问:
Website for Groovy Katas
Am planning to learn Groovy the Kata way. Is there any source similar to RubyQuiz for Groovy Katas ?</p>

答: Check out the Groovy Koans at https://github.com/cjudd/groovy_koans.</p>

ContentLicense: CC BY-SA 2.5

Title: Website for Groovy Katas


问:
Remove whitespace from first and last character on multiple headline sizes
I try to get div fitting headlines, so far so good. But know I got problems with the default whitespace of the characters (
particularly with the even ones like I,L,P,H). I've tried to manage it with the letter spacing (doesn't work), than I've tried to solve it with text justification (didn't get a solution as well)... Does anybody know a way to handle it? Thanks

function scaleHeader() {
  var vw = ($(window).width())* 0.01;
  console.log(vw)
  var scalable = document.querySelectorAll('h1');
  for (var i = 0; i < scalable.length; i++) {
    var scalableContainer = scalable[i].parentNode;
    scalable[i].style.transform = 'scale(1)';
    var scalableContainerWidth = scalableContainer.offsetWidth;

    var scalableWidth = scalable[i].offsetWidth;
    scalable[i].style.transform = 'scale(' + scalableContainerWidth / scalableWidth + ')';

    var firstletter = $(scalable[i]).text().slice(0,1);
    var lastletter = $(scalable[i]).text().slice(-1);

    if((firstletter.match(/(B|D|E|F|H|I|K|L|M|N|P|R|U|b|i|k|l|m|n|p|r)/)) && (lastletter.match(/(I|U|i|j|l|q|u)/))){
      //Here I don't know what to do!
    }

    if ($(scalableContainer).text().match(/(g|y|j|q|p)/)){
      scalableContainer.style.height = scalable[i].getBoundingClientRect().height * 1.05 + 'px' ;
    } else {
      scalableContainer.style.height = scalable[i].getBoundingClientRect().height * 0.85 + 'px' ;
    }
  }
}

scaleHeader();
window.addEventListener('resize', scaleHeader);```
<pre class="snippet-code-css lang-css prettyprint-override"><code>* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  font-size: 32px;
  line-height: 32px;
}

body {
  font-family: sans-serif;
}

.third {
  display:inline-block;
  text-align: left;
  background-color: red;

  margin-bottom: 20px;
  width: 33vw;
  heigth: auto;
}

.half {
  display:inline-block;
  text-align: left;
  background-color: red;

  margin-bottom: 20px;
  width: 49.5vw;
  heigth: auto;
}

.scale--js {
  display: inline-block;
  transform-origin: 0 0;
  transform: translate3d( 0, 0, 0);
}</code>```

Mai

Juni

Heute

A'm full widthq

ij

Aktuell

```

答:
I solved it using a modifiction of bigtext.js. In case somebody else needs it.

/*! BigText - v1.0.1 - 2017-06-01
 * https://github.com/zachleat/bigtext
 * Copyright (c) 2017 Zach Leatherman (@zachleat)
 * MIT License */

(function(window, $) {
  "use strict";

  var counter = 0,
    $headCache = $('head'),
    oldBigText = window.BigText,
    oldjQueryMethod = $.fn.bigtext,
    BigText = {
      DEBUG_MODE: false,
      DEFAULT_MIN_FONT_SIZE_PX: null,
      DEFAULT_MAX_FONT_SIZE_PX: 100000000,
      GLOBAL_STYLE_ID: 'bigtext-style',
      STYLE_ID: 'bigtext-id',
      LINE_CLASS_PREFIX: 'bigtext-line',
      EXEMPT_CLASS: 'bigtext-exempt',
      noConflict: function(restore)
      {
        if(restore) {
          $.fn.bigtext = oldjQueryMethod;
          window.BigText = oldBigText;
        }
        return BigText;
      },
      supports: {
        wholeNumberFontSizeOnly: (function() {
          if( !( 'getComputedStyle' in window ) ) {
            return true;
          }
          var test = $('
').css({
              position: 'absolute',
              'font-size': '14.1px',
            }).insertBefore( $('script').eq(0) ),
            computedStyle = window.getComputedStyle( test[0], null );

          var ret = computedStyle && computedStyle.getPropertyValue( 'font-size' ) === '14px';
          test.remove();
          return ret;
        })()
      },
      init: function() {
        if(!$('#'+BigText.GLOBAL_STYLE_ID).length) {
          $headCache.append(BigText.generateStyleTag(BigText.GLOBAL_STYLE_ID, ['.bigtext * { white-space: nowrap; } .bigtext > * { display: block; }',
                                          '.bigtext .' + BigText.EXEMPT_CLASS + ', .bigtext .' + BigText.EXEMPT_CLASS + ' * { white-space: normal; }']));
        }
      },
      bindResize: function(eventName, resizeFunction) {
        var timeoutId;
        $(window).unbind(eventName).bind(eventName, function() {
          if( timeoutId ) {
            clearTimeout( timeoutId );
          }
          timeoutId = setTimeout( resizeFunction, 100 );
        });
      },
      getStyleId: function(id)
      {
        return BigText.STYLE_ID + '-' + id;
      },
      generateStyleTag: function(id, css)
      {
        return $('').attr('id', id);
      },
      clearCss: function(id)
      {
        var styleId = BigText.getStyleId(id);
        $('#' + styleId).remove();
      },
      generateCss: function(id, linesFontSizes, lineWordSpacings, minFontSizes)
      {
        var css = [];

        BigText.clearCss(id);

        for(var j=0, k=linesFontSizes.length; j<k; j++) {
          css.push('#' + id + ' .' + BigText.LINE_CLASS_PREFIX + j + ' {' +
            (minFontSizes[j] ? ' white-space: normal;' : '') +
            (linesFontSizes[j] ? ' font-size: ' + linesFontSizes[j] + 'px;' : '') +
            (lineWordSpacings[j] ? ' word-spacing: ' + lineWordSpacings[j] + 'px;' : '') +
            '}');
        }

        return BigText.generateStyleTag(BigText.getStyleId(id), css);
      },
      jQueryMethod: function(options)
      {
        BigText.init();

        options = $.extend({
          minfontsize: BigText.DEFAULT_MIN_FONT_SIZE_PX,
          maxfontsize: BigText.DEFAULT_MAX_FONT_SIZE_PX,
          childSelector: '',
          resize: true
        }, options || {});

        this.each(function()
        {
          var $t = $(this).addClass('bigtext'),
            maxWidth = $t.width(),
            id = $t.attr('id'),
            $children = options.childSelector ? $t.find( options.childSelector ) : $t.children();

          if(!id) {
            id = 'bigtext-id' + (counter++);
            $t.attr('id', id);
          }

          if(options.resize) {
            BigText.bindResize('resize.bigtext-event-' + id, function()
            {
              // TODO only call this if the width has changed.
              BigText.jQueryMethod.call($('#' + id), options);
            });
          }

          BigText.clearCss(id);

          $children.addClass(function(lineNumber, className)
          {
            // remove existing line classes.
            return [className.replace(new RegExp('\\b' + BigText.LINE_CLASS_PREFIX + '\\d+\\b'), ''),
                BigText.LINE_CLASS_PREFIX + lineNumber].join(' ');
          });

          var sizes = BigText.calculateSizes($t, $children, maxWidth, options.maxfontsize, options.minfontsize);
          $headCache.append(BigText.generateCss(id, sizes.fontSizes, sizes.wordSpacings, sizes.minFontSizes));

        });

        return this.trigger('bigtext:complete');
      },
      testLineDimensions: function($line, maxWidth, property, size, interval, units, previousWidth)
      {
        var width;
        previousWidth = typeof previousWidth === 'number' ? previousWidth : 0;
        $line.css(property, size + units);

        width = $line.width();

        if(width >= maxWidth) {
    // console.log(width, ' previous: ' + previousWidth, property + ' at ' + interval, 'prior: ' + (parseFloat(size) - interval), 'new:' + parseFloat(size));
          $line.css(property, '');

          if(width === maxWidth) {
            return {
              match: 'exact',
              size: parseFloat((parseFloat(size) - 0.1).toFixed(3))
            };
          }

          // Since this is an estimate, we calculate how far over the width we went with the new value.
          // If this is word-spacing (our last resort guess) and the over is less than the under, we keep the higher value.
          // Otherwise, we revert to the underestimate.
          var under = maxWidth - previousWidth,
            over = width - maxWidth;

          return {
            match: 'estimate',
            size: parseFloat((parseFloat(size) - (property === 'word-spacing' && previousWidth && ( over < under ) ? 0 : interval)).toFixed(3))
          };
        }

        return width;
      },
      calculateSizes: function($t, $children, maxWidth, maxFontSize, minFontSize)
      {
        var $c = $t.clone(true)
          .addClass('bigtext-cloned')
          .css({
            fontFamily: $t.css('font-family'),
            textTransform: $t.css('text-transform'),
            wordSpacing: $t.css('word-spacing'),
            letterSpacing: $t.css('letter-spacing'),
            position: 'absolute',
            left: BigText.DEBUG_MODE ? 0 : -9999,
            top: BigText.DEBUG_MODE ? 0 : -9999
          })
          .appendTo(document.body);

        // font-size isn't the only thing we can modify, we can also mess with:
        // word-spacing and letter-spacing. WebKit does not respect subpixel
        // letter-spacing, word-spacing, or font-size.
        // TODO try -webkit-transform: scale() as a workaround.
        var fontSizes = [],
          wordSpacings = [],
          minFontSizes = [],
          ratios = [];

        $children.css('float', 'left').each(function() {
          var $line = $(this),
            // TODO replace 8, 4 with a proportional size to the calculated font-size.
            intervals = BigText.supports.wholeNumberFontSizeOnly ? [8, 4, 1] : [8, 4, 1, 0.1],
            lineMax,
            newFontSize;

          if($line.hasClass(BigText.EXEMPT_CLASS)) {
            fontSizes.push(null);
            ratios.push(null);
            minFontSizes.push(false);
            return;
          }

          // TODO we can cache this ratio?
          var autoGuessSubtraction = 32, // font size in px
            currentFontSize = parseFloat($line.css('font-size')),
            ratio = ( $line.width() / currentFontSize ).toFixed(6);

          newFontSize = parseInt( maxWidth / ratio, 10 ) - autoGuessSubtraction;

          outer: for(var m=0, n=intervals.length; m<n; m++) {
            inner: for(var j=1, k=10; j<=k; j++) {
              if(newFontSize + j*intervals[m] > maxFontSize) {
                newFontSize = maxFontSize;
                break outer;
              }

              lineMax = BigText.testLineDimensions($line, maxWidth, 'font-size', newFontSize + j*intervals[m], intervals[m], 'px', lineMax);
              if(typeof lineMax !== 'number') {
                newFontSize = lineMax.size;

                if(lineMax.match === 'exact') {
                  break outer;
                }
                break inner;
              }
            }
          }

          ratios.push(maxWidth / newFontSize);

          if(newFontSize > maxFontSize) {
            fontSizes.push(maxFontSize);
            minFontSizes.push(false);
          } else if(!!minFontSize && newFontSize < minFontSize) {
            fontSizes.push(minFontSize);
            minFontSizes.push(true);
          } else {
            fontSizes.push(newFontSize);
            minFontSizes.push(false);
          }
        }).each(function(lineNumber) {
          var $line = $(this),
            wordSpacing = 0,
            interval = 1,
            maxWordSpacing;

          if($line.hasClass(BigText.EXEMPT_CLASS)) {
            wordSpacings.push(null);
            return;
          }

          // must re-use font-size, even though it was removed above.
          $line.css('font-size', fontSizes[lineNumber] + 'px');

          for(var m=1, n=3; m<n; m+=interval) {
            maxWordSpacing = BigText.testLineDimensions($line, maxWidth, 'word-spacing', m, interval, 'px', maxWordSpacing);
            if(typeof maxWordSpacing !== 'number') {
              wordSpacing = maxWordSpacing.size;
              break;
            }
          }

          $line.css('font-size', '');
          wordSpacings.push(wordSpacing);
        }).removeAttr('style');

        if( !BigText.DEBUG_MODE ) {
          $c.remove();
        } else {
          $c.css({
            'background-color': 'rgba(255,255,255,.4)'
          });
        }

        return {
          fontSizes: fontSizes,
          wordSpacings: wordSpacings,
          ratios: ratios,
          minFontSizes: minFontSizes
        };
      }
    };

  $.fn.bigtext = BigText.jQueryMethod;
  window.BigText = BigText;

})(this, jQuery);

//Here is my modification

$(document).ready(function(){

  $('h1').bigtext({
    childSelector: '> p',
  });

  $('p').each(function() {
    var firstletter = $(this).text().slice(0,1);
    var lastletter = $(this).text().slice(-1);
    var fontSize = $(this).css('fontSize');
    var fontSizeRaw = parseInt(fontSize, 10);

    if((firstletter.match(/(B|D|E|F|H|I|K|L|M|N|P|R|U|b|i|k|l|m|n|p|r)/)) && (lastletter.match(/(I|U|i|j|l|q|u)/))){
      var mrg= - fontSizeRaw / 36;

      $(this).html(function (i, html) {
        var chars = $.trim(html).split("");
        return '' + chars.join('') + '';
      });

      $(this).children(":first").css('marginLeft', mrg + 'px');
      $(this).children(":last").css('marginRight', mrg + 'px');

    } else if (firstletter.match(/(B|D|E|F|H|I|K|L|M|N|P|R|U|b|i|k|l|m|n|p|r)/)){
      var mrg= - fontSizeRaw / 36;

      $(this).html(function (i, html) {
        var chars = $.trim(html).split("");
        return html.replace(/\S/g, '$&');
      });

      $(this).children(":first").css('marginLeft', mrg + 'px');

    } else if (lastletter.match(/(I|U|i|j|l|q|u)/)){
      var mrg= - fontSizeRaw / 36;

      $(this).html(function (i, html) {
        var chars = $.trim(html).split("");
        return html.replace(/\S/g, '$&');
      });

      $(this).children(":last").css('marginRight', mrg + 'px');

    } else {

      $(this).html(function (i, html) {
        var chars = $.trim(html).split("");
        return html.replace(/\S/g, '$&');
      });

    }

    if ($(this).text().match(/(g|y|j|q|p)/)){
      $(this).children().css('marginTop', '-' + fontSizeRaw * 0.1 + 'px' );
      $(this).css('height', fontSizeRaw * 0.80 + 'px' );
    } else {
      $(this).children().css('marginTop', '-' + fontSizeRaw * 0.1 + 'px' );
      $(this).css('height', fontSizeRaw * 0.63 + 'px' );
    }

  });
});```
<pre class="snippet-code-css lang-css prettyprint-override"><code>*{
  font-family: "FoundersGroteskXCond-Med", sans-serif;
  margin: 0;
  padding: 0;
}

h1{
 font-weight: normal;
 margin: 0 !important
}

.quater{
  height: auto;
  width: 32.33333vw;
  background-color: red;
}

.half{
  width: 65.666vw;
  background-color: red;
}

.grid > div{
  display: inline-block;
 margin: 0.5vw;
}

.ll{
  zoom: 103%;
}

p {
 padding-top: 0;
    display: flex !important;
    justify-content: space-between;
    /*background-color: blue;*/
}</code>```

Wolfgang Mattheuer

Palawi

Rog

News

Tanja Zimmermann

Heute

News

Heute

Juli

Aktuell

lll

 ```

ContentLicense: CC BY-SA 3.0

Body:
I try to get div fitting headlines, so far so good. But know I got problems with the default whitespace of the characters (
particularly with the even ones like I,L,P,H). I've tried to manage it with the letter spacing (doesn't work), than I've tried to solve it with text justification (didn't get a solution as well)... Does anybody know a way to handle it? Thanks

function scaleHeader() {
  var vw = ($(window).width())* 0.01;
  console.log(vw)
  var scalable = document.querySelectorAll('h1');
  for (var i = 0; i < scalable.length; i++) {
    var scalableContainer = scalable[i].parentNode;
    scalable[i].style.transform = 'scale(1)';
    var scalableContainerWidth = scalableContainer.offsetWidth;

    var scalableWidth = scalable[i].offsetWidth;
    scalable[i].style.transform = 'scale(' + scalableContainerWidth / scalableWidth + ')';

    var firstletter = $(scalable[i]).text().slice(0,1);
    var lastletter = $(scalable[i]).text().slice(-1);

    if((firstletter.match(/(B|D|E|F|H|I|K|L|M|N|P|R|U|b|i|k|l|m|n|p|r)/)) && (lastletter.match(/(I|U|i|j|l|q|u)/))){
      //Here I don't know what to do!
    }

    if ($(scalableContainer).text().match(/(g|y|j|q|p)/)){
      scalableContainer.style.height = scalable[i].getBoundingClientRect().height * 1.05 + 'px' ;
    } else {
      scalableContainer.style.height = scalable[i].getBoundingClientRect().height * 0.85 + 'px' ;
    }
  }
}

scaleHeader();
window.addEventListener('resize', scaleHeader);

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  font-size: 32px;
  line-height: 32px;
}

body {
  font-family: sans-serif;
}

.third {
  display:inline-block;
  text-align: left;
  background-color: red;

  margin-bottom: 20px;
  width: 33vw;
  heigth: auto;
}

.half {
  display:inline-block;
  text-align: left;
  background-color: red;

  margin-bottom: 20px;
  width: 49.5vw;
  heigth: auto;
}

.scale--js {
  display: inline-block;
  transform-origin: 0 0;
  transform: translate3d( 0, 0, 0);
}

Mai

Juni

Heute

A'm full widthq

ij

Aktuell

Body:
I solved it using a modifiction of bigtext.js. In case somebody else needs it.

/*! BigText - v1.0.1 - 2017-06-01
 * https://github.com/zachleat/bigtext
 * Copyright (c) 2017 Zach Leatherman (@zachleat)
 * MIT License */

(function(window, $) {
  "use strict";

  var counter = 0,
    $headCache = $('head'),
    oldBigText = window.BigText,
    oldjQueryMethod = $.fn.bigtext,
    BigText = {
      DEBUG_MODE: false,
      DEFAULT_MIN_FONT_SIZE_PX: null,
      DEFAULT_MAX_FONT_SIZE_PX: 100000000,
      GLOBAL_STYLE_ID: 'bigtext-style',
      STYLE_ID: 'bigtext-id',
      LINE_CLASS_PREFIX: 'bigtext-line',
      EXEMPT_CLASS: 'bigtext-exempt',
      noConflict: function(restore)
      {
        if(restore) {
          $.fn.bigtext = oldjQueryMethod;
          window.BigText = oldBigText;
        }
        return BigText;
      },
      supports: {
        wholeNumberFontSizeOnly: (function() {
          if( !( 'getComputedStyle' in window ) ) {
            return true;
          }
          var test = $('<div/>').css({
              position: 'absolute',
              'font-size': '14.1px',
            }).insertBefore( $('script').eq(0) ),
            computedStyle = window.getComputedStyle( test[0], null );

          var ret = computedStyle && computedStyle.getPropertyValue( 'font-size' ) === '14px';
          test.remove();
          return ret;
        })()
      },
      init: function() {
        if(!$('#'+BigText.GLOBAL_STYLE_ID).length) {
          $headCache.append(BigText.generateStyleTag(BigText.GLOBAL_STYLE_ID, ['.bigtext * { white-space: nowrap; } .bigtext > * { display: block; }',
                                          '.bigtext .' + BigText.EXEMPT_CLASS + ', .bigtext .' + BigText.EXEMPT_CLASS + ' * { white-space: normal; }']));
        }
      },
      bindResize: function(eventName, resizeFunction) {
        var timeoutId;
        $(window).unbind(eventName).bind(eventName, function() {
          if( timeoutId ) {
            clearTimeout( timeoutId );
          }
          timeoutId = setTimeout( resizeFunction, 100 );
        });
      },
      getStyleId: function(id)
      {
        return BigText.STYLE_ID + '-' + id;
      },
      generateStyleTag: function(id, css)
      {
        return $('<style>' + css.join('\n') + '</style>').attr('id', id);
      },
      clearCss: function(id)
      {
        var styleId = BigText.getStyleId(id);
        $('#' + styleId).remove();
      },
      generateCss: function(id, linesFontSizes, lineWordSpacings, minFontSizes)
      {
        var css = [];

        BigText.clearCss(id);

        for(var j=0, k=linesFontSizes.length; j<k; j++) {
          css.push('#' + id + ' .' + BigText.LINE_CLASS_PREFIX + j + ' {' +
            (minFontSizes[j] ? ' white-space: normal;' : '') +
            (linesFontSizes[j] ? ' font-size: ' + linesFontSizes[j] + 'px;' : '') +
            (lineWordSpacings[j] ? ' word-spacing: ' + lineWordSpacings[j] + 'px;' : '') +
            '}');
        }

        return BigText.generateStyleTag(BigText.getStyleId(id), css);
      },
      jQueryMethod: function(options)
      {
        BigText.init();

        options = $.extend({
          minfontsize: BigText.DEFAULT_MIN_FONT_SIZE_PX,
          maxfontsize: BigText.DEFAULT_MAX_FONT_SIZE_PX,
          childSelector: '',
          resize: true
        }, options || {});

        this.each(function()
        {
          var $t = $(this).addClass('bigtext'),
            maxWidth = $t.width(),
            id = $t.attr('id'),
            $children = options.childSelector ? $t.find( options.childSelector ) : $t.children();

          if(!id) {
            id = 'bigtext-id' + (counter++);
            $t.attr('id', id);
          }

          if(options.resize) {
            BigText.bindResize('resize.bigtext-event-' + id, function()
            {
              // TODO only call this if the width has changed.
              BigText.jQueryMethod.call($('#' + id), options);
            });
          }

          BigText.clearCss(id);

          $children.addClass(function(lineNumber, className)
          {
            // remove existing line classes.
            return [className.replace(new RegExp('\\b' + BigText.LINE_CLASS_PREFIX + '\\d+\\b'), ''),
                BigText.LINE_CLASS_PREFIX + lineNumber].join(' ');
          });

          var sizes = BigText.calculateSizes($t, $children, maxWidth, options.maxfontsize, options.minfontsize);
          $headCache.append(BigText.generateCss(id, sizes.fontSizes, sizes.wordSpacings, sizes.minFontSizes));

        });

        return this.trigger('bigtext:complete');
      },
      testLineDimensions: function($line, maxWidth, property, size, interval, units, previousWidth)
      {
        var width;
        previousWidth = typeof previousWidth === 'number' ? previousWidth : 0;
        $line.css(property, size + units);

        width = $line.width();

        if(width >= maxWidth) {
    // console.log(width, ' previous: ' + previousWidth, property + ' at ' + interval, 'prior: ' + (parseFloat(size) - interval), 'new:' + parseFloat(size));
          $line.css(property, '');

          if(width === maxWidth) {
            return {
              match: 'exact',
              size: parseFloat((parseFloat(size) - 0.1).toFixed(3))
            };
          }

          // Since this is an estimate, we calculate how far over the width we went with the new value.
          // If this is word-spacing (our last resort guess) and the over is less than the under, we keep the higher value.
          // Otherwise, we revert to the underestimate.
          var under = maxWidth - previousWidth,
            over = width - maxWidth;

          return {
            match: 'estimate',
            size: parseFloat((parseFloat(size) - (property === 'word-spacing' && previousWidth && ( over < under ) ? 0 : interval)).toFixed(3))
          };
        }

        return width;
      },
      calculateSizes: function($t, $children, maxWidth, maxFontSize, minFontSize)
      {
        var $c = $t.clone(true)
          .addClass('bigtext-cloned')
          .css({
            fontFamily: $t.css('font-family'),
            textTransform: $t.css('text-transform'),
            wordSpacing: $t.css('word-spacing'),
            letterSpacing: $t.css('letter-spacing'),
            position: 'absolute',
            left: BigText.DEBUG_MODE ? 0 : -9999,
            top: BigText.DEBUG_MODE ? 0 : -9999
          })
          .appendTo(document.body);

        // font-size isn't the only thing we can modify, we can also mess with:
        // word-spacing and letter-spacing. WebKit does not respect subpixel
        // letter-spacing, word-spacing, or font-size.
        // TODO try -webkit-transform: scale() as a workaround.
        var fontSizes = [],
          wordSpacings = [],
          minFontSizes = [],
          ratios = [];

        $children.css('float', 'left').each(function() {
          var $line = $(this),
            // TODO replace 8, 4 with a proportional size to the calculated font-size.
            intervals = BigText.supports.wholeNumberFontSizeOnly ? [8, 4, 1] : [8, 4, 1, 0.1],
            lineMax,
            newFontSize;

          if($line.hasClass(BigText.EXEMPT_CLASS)) {
            fontSizes.push(null);
            ratios.push(null);
            minFontSizes.push(false);
            return;
          }

          // TODO we can cache this ratio?
          var autoGuessSubtraction = 32, // font size in px
            currentFontSize = parseFloat($line.css('font-size')),
            ratio = ( $line.width() / currentFontSize ).toFixed(6);

          newFontSize = parseInt( maxWidth / ratio, 10 ) - autoGuessSubtraction;

          outer: for(var m=0, n=intervals.length; m<n; m++) {
            inner: for(var j=1, k=10; j<=k; j++) {
              if(newFontSize + j*intervals[m] > maxFontSize) {
                newFontSize = maxFontSize;
                break outer;
              }

              lineMax = BigText.testLineDimensions($line, maxWidth, 'font-size', newFontSize + j*intervals[m], intervals[m], 'px', lineMax);
              if(typeof lineMax !== 'number') {
                newFontSize = lineMax.size;

                if(lineMax.match === 'exact') {
                  break outer;
                }
                break inner;
              }
            }
          }

          ratios.push(maxWidth / newFontSize);

          if(newFontSize > maxFontSize) {
            fontSizes.push(maxFontSize);
            minFontSizes.push(false);
          } else if(!!minFontSize && newFontSize < minFontSize) {
            fontSizes.push(minFontSize);
            minFontSizes.push(true);
          } else {
            fontSizes.push(newFontSize);
            minFontSizes.push(false);
          }
        }).each(function(lineNumber) {
          var $line = $(this),
            wordSpacing = 0,
            interval = 1,
            maxWordSpacing;

          if($line.hasClass(BigText.EXEMPT_CLASS)) {
            wordSpacings.push(null);
            return;
          }

          // must re-use font-size, even though it was removed above.
          $line.css('font-size', fontSizes[lineNumber] + 'px');

          for(var m=1, n=3; m<n; m+=interval) {
            maxWordSpacing = BigText.testLineDimensions($line, maxWidth, 'word-spacing', m, interval, 'px', maxWordSpacing);
            if(typeof maxWordSpacing !== 'number') {
              wordSpacing = maxWordSpacing.size;
              break;
            }
          }

          $line.css('font-size', '');
          wordSpacings.push(wordSpacing);
        }).removeAttr('style');

        if( !BigText.DEBUG_MODE ) {
          $c.remove();
        } else {
          $c.css({
            'background-color': 'rgba(255,255,255,.4)'
          });
        }

        return {
          fontSizes: fontSizes,
          wordSpacings: wordSpacings,
          ratios: ratios,
          minFontSizes: minFontSizes
        };
      }
    };

  $.fn.bigtext = BigText.jQueryMethod;
  window.BigText = BigText;

})(this, jQuery);

//Here is my modification

$(document).ready(function(){

  $('h1').bigtext({
    childSelector: '> p',
  });

  $('p').each(function() {
    var firstletter = $(this).text().slice(0,1);
    var lastletter = $(this).text().slice(-1);
    var fontSize = $(this).css('fontSize');
    var fontSizeRaw = parseInt(fontSize, 10);

    if((firstletter.match(/(B|D|E|F|H|I|K|L|M|N|P|R|U|b|i|k|l|m|n|p|r)/)) && (lastletter.match(/(I|U|i|j|l|q|u)/))){
      var mrg= - fontSizeRaw / 36;

      $(this).html(function (i, html) {
        var chars = $.trim(html).split("");
        return '<span>' + chars.join('</span><span>') + '</span>';
      });

      $(this).children(":first").css('marginLeft', mrg + 'px');
      $(this).children(":last").css('marginRight', mrg + 'px');

    } else if (firstletter.match(/(B|D|E|F|H|I|K|L|M|N|P|R|U|b|i|k|l|m|n|p|r)/)){
      var mrg= - fontSizeRaw / 36;

      $(this).html(function (i, html) {
        var chars = $.trim(html).split("");
        return html.replace(/\S/g, '<span>$&</span>');
      });

      $(this).children(":first").css('marginLeft', mrg + 'px');

    } else if (lastletter.match(/(I|U|i|j|l|q|u)/)){
      var mrg= - fontSizeRaw / 36;

      $(this).html(function (i, html) {
        var chars = $.trim(html).split("");
        return html.replace(/\S/g, '<span>$&</span>');
      });

      $(this).children(":last").css('marginRight', mrg + 'px');

    } else {

      $(this).html(function (i, html) {
        var chars = $.trim(html).split("");
        return html.replace(/\S/g, '<span>$&</span>');
      });

    }

    if ($(this).text().match(/(g|y|j|q|p)/)){
      $(this).children().css('marginTop', '-' + fontSizeRaw * 0.1 + 'px' );
      $(this).css('height', fontSizeRaw * 0.80 + 'px' );
    } else {
      $(this).children().css('marginTop', '-' + fontSizeRaw * 0.1 + 'px' );
      $(this).css('height', fontSizeRaw * 0.63 + 'px' );
    }

  });
});

*{
  font-family: "FoundersGroteskXCond-Med", sans-serif;
  margin: 0;
  padding: 0;
}

h1{
 font-weight: normal;
 margin: 0 !important
}

.quater{
  height: auto;
  width: 32.33333vw;
  background-color: red;
}

.half{
  width: 65.666vw;
  background-color: red;
}

.grid > div{
  display: inline-block;
 margin: 0.5vw;
}

.ll{
  zoom: 103%;
}

p {
 padding-top: 0;
    display: flex !important;
    justify-content: space-between;
    /*background-color: blue;*/
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="grid">

  <div class="quater">
    <h1>
      <p>Wolfgang Mattheuer</p>
    </h1>
  </div>

  <div class="quater">
    <h1>
      <p>Palawi</p>
    </h1>
  </div>

  <div class="quater">
    <h1>
      <p>Rog</p>
    </h1>
  </div>

  <div class="quater">
    <h1>
      <p>News</p>
    </h1>
  </div>

    <div class="half">
    <h1>
      <p>Tanja Zimmermann</p>
    </h1>
  </div>

  <div class="quater">
    <h1>
      <p>Heute</p>
    </h1>
  </div>

  <div class="quater">
    <h1>
      <p>News</p>
    </h1>
  </div>

  <div class="quater">
    <h1>
      <p>Heute</p>
    </h1>
  </div>

  <div class="half">
    <h1>
      <p>Juli</p>
    </h1>
  </div>

  <div class="quater">
    <h1>
      <p>Aktuell</p>
    </h1>
  </div>

  <div class="quater">
    <h1>
      <p>lll</p>
    </h1>
  </div>

 </body>


问:
A way to subclass NamedTuple for purposes of typechecking
I have several namedtuples that share some fields. I have a function that accepts these tuples and is guaranteed to only interact with the shared fields. I want to typecheck such code in mypy.

An example of the code would be:

```<code>from typing import NamedTuple

class Base(NamedTuple):
    x: int
    y: int

class BaseExtended(NamedTuple):
    x: int
    y: int
    z: str

def DoSomething(tuple: Base):
    return tuple.x + tuple.y

base = Base(3, 4)
base_extended = BaseExtended(5, 6, 'foo')

DoSomething(base)
DoSomething(base_extended)
</code>```

When I run mypy on this code, I get a predictable error:

mypy_example.py:20: error: Argument 1 to "DoSomething" has incompatible type "BaseExtended"; expected "Base"

Is there no way to structure my code and keep mypy typechecking? I cannot inherit BaseExtended from Base, since there's a bug in the NamedTuple inheritance implementation.

I don't want to use an ugly Union[Base, BaseExtended] either, since this breaks when I try to typecheck a List, since List[Union[Base, BaseExtended]] is not equal to List[BaseExtended] due to some mypy magic about variant/covariant types.

Should I just abandon the idea?

答: There is PEP 544 that proposes an extension to type system that will allow structural subtyping (static duck typing). Also runtime implementation of typing.NamedTuple will be improved soon, probably in Python 3.6.2 end of June (this will be also backported via typing on PyPI).

ContentLicense: CC BY-SA 4.0

Body:
I have several namedtuples that share some fields. I have a function that accepts these tuples and is guaranteed to only interact with the shared fields. I want to typecheck such code in mypy.

An example of the code would be:

from typing import NamedTuple

class Base(NamedTuple):
    x: int
    y: int

class BaseExtended(NamedTuple):
    x: int
    y: int
    z: str

def DoSomething(tuple: Base):
    return tuple.x + tuple.y

base = Base(3, 4)
base_extended = BaseExtended(5, 6, 'foo')

DoSomething(base)
DoSomething(base_extended)

When I run mypy on this code, I get a predictable error:

mypy_example.py:20: error: Argument 1 to "DoSomething" has incompatible type "BaseExtended"; expected "Base"

Is there no way to structure my code and keep mypy typechecking? I cannot inherit BaseExtended from Base, since there's a bug in the NamedTuple inheritance implementation.

I don't want to use an ugly Union[Base, BaseExtended] either, since this breaks when I try to typecheck a List, since List[Union[Base, BaseExtended]] is not equal to List[BaseExtended] due to some mypy magic about variant/covariant types.

Should I just abandon the idea?


问:
Discard variables through use of dot and dollar
I'm a Haskell beginner and I want to know why we can discard certain variables when using certain operators, for example:

```<code>     last xs = head (reverse xs)
     last'   = head . reverse
</code>```

Another example:

```<code>     example p xs = length (filter p xs)
     example' p = length . filter p
</code>```

Why can't we toss the p in this function?

答:
This is called point-free notation. For your example, it is:

```<code>example' = (length .) . filter
</code>```

though it is harder to comprehend, in my opinion.

There is a convenient tool to generate point-free version: pointfree.io

Body:
I'm a Haskell beginner and I want to know why we can discard certain variables when using certain operators, for example:

     last xs = head (reverse xs)
     last'   = head . reverse

Another example:

     example p xs = length (filter p xs)
     example' p = length . filter p

Why can't we toss the p in this function?

Body:
This is called point-free notation. For your example, it is:

example' = (length .) . filter

though it is harder to comprehend, in my opinion.

There is a convenient tool to generate point-free version: pointfree.io


问:
Initializing Select value dynamically in angular2
I am setting value of select option in a loop . Have a look at the code

```<code><div *ngFor="let sport of sport_data;" class="row">
  <select [(ngModel)]="sports.value" class="form-control">
      <option value="football">Sports</option>
      <option value="cricket">Cricket</option>
  </select>
</div>
</code>```

Here sport_data is the array of list of sports . Its not working fine . Is their any other way to set default value of select element?

答:
Should the select have a binding to the "sport" variable of the *ngFor? In that case it seems that you have a typo, as you bind the ngModel to "sports" and not "sport". The code should look like this:

```<code><div *ngFor="let sport of sport_data;" class="row">
  <select [(ngModel)]="sport.value" class="form-control">
      <option value="football">Sports</option>
      <option value="cricket">Cricket</option>
  </select>
</div>
</code>```

As you asked for it, a different approach could be to use the (change) event on the select to set the value and the [selected] binding for the option to be selected.

Body:
I am setting value of select option in a loop . Have a look at the code

  <select [(ngModel)]="sports.value" class="form-control">
      <option value="football">Sports</option>
      <option value="cricket">Cricket</option>
  </select>

Here sport_data is the array of list of sports . Its not working fine . Is their any other way to set default value of select element?

Body:
Should the select have a binding to the "sport" variable of the *ngFor? In that case it seems that you have a typo, as you bind the ngModel to "sports" and not "sport". The code should look like this:

<div *ngFor="let sport of sport_data;" class="row">
  <select [(ngModel)]="sport.value" class="form-control">
      <option value="football">Sports</option>
      <option value="cricket">Cricket</option>
  </select>
</div>

As you asked for it, a different approach could be to use the (change) event on the select to set the value and the [selected] binding for the option to be selected.


问:
Showing Greeting Message in Javascript
How can I display a greeting message according to the time of the day in javascript?</p>

```<code>var greetdate=new Date()
var hours=greetdate.getHours()

document.write('<h2>Hello! Good Morning! Have a nice day.</h2>')

document.write('<h2>Good Noon Visitor! </h2>')

//MESSAGE FOR AFTERNOON
document.write('<h2>Good Afternoon! </h2>')

//MESSAGE FOR EVENING (6pm-8pm)
document.write('<h2>Good Evening! </h2>')

//MESSAGE FOR NIGHT (9pm-11pm)
document.write('<h2>Good Night! </h2>')

//MESSAGE FOR LATE NIGHT (12pm-4am)
document.write('<h2>Wow! You`re still awake. Working Late?</h2>')
</code>```

答:
```<code>function writeWelcomeMessage() {
    var d = new Date();
    var h = d.getHours();

    if(h < 12) {
        document.write('<h2>Hello! Good Morning! Have a nice day.</h2>')
    } else if(h < 18) {
        document.write('<h2>Hello! Good Day.</h2>')
    }
    // etc
}
</code>```

Title: Showing Greeting Message in Javascript

Body:
How can I display a greeting message according to the time of the day in javascript?

var greetdate=new Date()
var hours=greetdate.getHours()

document.write('
Hello! Good Morning! Have a nice day.
')

document.write('
Good Noon Visitor!
')

//MESSAGE FOR AFTERNOON
document.write('
Good Afternoon!
')

//MESSAGE FOR EVENING (6pm-8pm)
document.write('
Good Evening!
')

//MESSAGE FOR NIGHT (9pm-11pm)
document.write('
Good Night!
')

//MESSAGE FOR LATE NIGHT (12pm-4am)
document.write('
Wow! You`re still awake. Working Late?
')


问:
gluCylinder with glTranslate
I'm having a problem where I've made a cylinder with following code, and I've been trying to move it (back, so that the center of it is where the grey beam is).

However, the output is not moving the cylinder at all, and I'm failing to spot what the issue is?

```<code>GLfloat plane[] = {0.0, 0.0, 1.0, 1.0};
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, plane);
glBegin(GL_POLYGON);
    glPushMatrix();
        glTranslatef(0.0f, 3.0f, -11.0f);
        GLUquadricObj *quad = gluNewQuadric();
        gluCylinder(quad, 2, 2, 22, 30, 30);
    glPopMatrix();
glEnd();

glFlush(); /* Complete any pending operations */
glutSwapBuffers();
</code>```

答: You have to remove the glBegin and glEnd calls. None of the functions you called there are allowed between those two commands.

Title: gluCylinder with glTranslate

Body:
I'm having a problem where I've made a cylinder with following code, and I've been trying to move it (back, so that the center of it is where the grey beam is).

However, the output is not moving the cylinder at all, and I'm failing to spot what the issue is?

GLfloat plane[] = {0.0, 0.0, 1.0, 1.0};
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, plane);
glBegin(GL_POLYGON);
    glPushMatrix();
        glTranslatef(0.0f, 3.0f, -11.0f);
        GLUquadricObj *quad = gluNewQuadric();
        gluCylinder(quad, 2, 2, 22, 30, 30);
    glPopMatrix();
glEnd();

glFlush(); /* Complete any pending operations */
glutSwapBuffers();


问:
How to assign the output of a program to a variable in a DCL com script on VMS?
For example, I have a perl script p.pl that writes "5" to stdout. I'd like to assign that output to a variable like so:</p>

```<code>$ x = perl p.pl ! not working code
$ ! now x would be 5
</code>```

答:
The PIPE command allows you to do Unix-ish pipelining, but DCL is not bash.  Getting the output assigned to a symbol is tricky.  Each PIPE segment runs in a separate subprocess (like Unix) and there's no way to return a symbol from a subprocess.  AFAIK, there's no bash equivalent of assigning stdout to a variable.

The typical approach is to write (redirect) the output to a file and then read it back:

```<code> $ PIPE perl p.pl > temp.txt
 $ open t temp.txt
 $ read t x
 $ close t
</code>```

Another approach is to assign the return value as a JOB logical which is shared by all subprocesses.  This can be done as a one-liner using PIPE:

```<code> $ PIPE perl p.pl | DEFINE/JOB RET_VALUE @SYS$PIPE
 $ x = f$logical("RET_VALUE")
</code>```

Since the "RET_VALUE" is shared by all processes in the job, you have to be careful of side-effects.

Body:
For example, I have a perl script p.pl that writes "5" to stdout. I'd like to assign that output to a variable like so:

$ x = perl p.pl ! not working code
$ ! now x would be 5

Body:
The PIPE command allows you to do Unix-ish pipelining, but DCL is not bash.  Getting the output assigned to a symbol is tricky.  Each PIPE segment runs in a separate subprocess (like Unix) and there's no way to return a symbol from a subprocess.  AFAIK, there's no bash equivalent of assigning stdout to a variable.

The typical approach is to write (redirect) the output to a file and then read it back:

 $ PIPE perl p.pl > temp.txt
 $ open t temp.txt
 $ read t x
 $ close t

Another approach is to assign the return value as a JOB logical which is shared by all subprocesses.  This can be done as a one-liner using PIPE:

 $ PIPE perl p.pl | DEFINE/JOB RET_VALUE @SYS$PIPE
 $ x = f$logical("RET_VALUE")

Since the "RET_VALUE" is shared by all processes in the job, you have to be careful of side-effects.


问:
Javascript display name of div
I have a container with divs inside, using Javascript I am trying to open an alert box for each item found displaying the 'name' of the div...

items = document.getElementsByClassName("single_item");

for (i = 0; i < items.length; i++) {
    alert("This is an item - the name is...")
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><div class="container">
    <div name="item1" class="single_item">
        Item 1
    </div>
    <div name="item2" class="single_item">
        Item 2
    </div>
    <div name="item3" class="single_item">
        Item 3
    </div>
    <div name="item4" class="single_item">
        Item 4
    </div>
</div></code>```

I am stuck trying to access the name value, anyone have an example I can look at?

答:
Use Following code</p>

```<code>for (i = 0; i < items.length; i++) {
    var nameValue = item[i].getAttribute('name');
    alert("This is an item - the name is " + nameValue);
}
</code>```

Title: Javascript display name of div

Body:
I have a container with divs inside, using Javascript I am trying to open an alert box for each item found displaying the 'name' of the div...

items = document.getElementsByClassName("single_item");

for (i = 0; i < items.length; i++) {
    alert("This is an item - the name is...")
}

        Item 1

        Item 2

        Item 3

        Item 4

I am stuck trying to access the name value, anyone have an example I can look at?

Body:
Use Following code

for (i = 0; i < items.length; i++) {
    var nameValue = item[i].getAttribute('name');
    alert("This is an item - the name is " + nameValue);
}


问:
couldn't find php.ini file
I'm trying to Install the php.ini file as mentioned here

When I tried to locate that file on my laptop, this is the output.

```<code>$: locate php.ini
/etc/php/7.0/apache2/php.ini
/etc/php/7.0/cli/php.ini
</code>```

so I tried to copy that file tp another location like this:

```<code>$: sudo cp /etc/php/7.0/apache2/php.ini /usr/local/lib/php.ini
cp: cannot stat '/etc/php/7.0/apache2/php.ini': No such file or directory
</code>```

So, I checked if the file is there or not, and ls couldn't show the file.

```<code>/etc/php/7.0/apache2$ ls
conf.d
</code>```

there was no php.ini file. And it is the same case with the php.ini file in /etc/php/7.0/cli/

Can someone tell me what exactly is happening?
and what happens of we don't install php.ini file?

答: The php.ini file stores very important configuration settings and it is required for PHP to start. From the tutorial, I it mentions that php.ini is in the PHP zip file that you downloaded. Simply copy the file from the zip file to /usr/local/lib/</p>

Title: couldn't find php.ini file

Body:
I'm trying to Install the php.ini file as mentioned here

When I tried to locate that file on my laptop, this is the output.

$: locate php.ini
/etc/php/7.0/apache2/php.ini
/etc/php/7.0/cli/php.ini

so I tried to copy that file tp another location like this:

$: sudo cp /etc/php/7.0/apache2/php.ini /usr/local/lib/php.ini
cp: cannot stat '/etc/php/7.0/apache2/php.ini': No such file or directory

So, I checked if the file is there or not, and ls couldn't show the file.

/etc/php/7.0/apache2$ ls
conf.d

there was no php.ini file. And it is the same case with the php.ini file in /etc/php/7.0/cli/

Can someone tell me what exactly is happening?
and what happens of we don't install php.ini file?


问:
Match all keywords using like in group MySQL
I have a table of keywords (ID,ean,keyword) and another table with product details. I want the search to return EANs where all keywords match at least once, however the closest I have got is the following, but this returns matches that have the first term in them 3 times for example.

To give an example, let's say I have a product called 'Generic headphones - iPhone, iPad, iPod' and I searched 'gen%' 'hea%' 'ip%' it would come back as a match, but it would also match 'Apple headphones - iPhone, iPad, iPod' due to the 3 ip words, which is not desired.

SQL Fiddle
I want EAN 1 to match only, so matches need to be at least 1 for each term.

Any help would be much appreciated.

```
SELECT     Count(keywords.ean) AS cc,
           products.*
FROM       keywords
INNER JOIN products
ON         products.ean = keywords.ean
WHERE      (
                      keyword LIKE 'gen%'
                                 || keyword like 'ip%'
                                 || keyword LIKE 'hea%')
GROUP BY   (keywords.ean)
HAVING     cc>=3
ORDER BY   `products`.`ean` ASC
```

UPDATE: This gets the desired results, but there must be more efficient ways to do this.

```
SELECT products.*
FROM products
INNER JOIN (SELECT ean, count(*) as tc1
                    FROM keywords
                    WHERE ( keyword like 'gen%' )
                    GROUP BY ean
                    HAVING tc1 > 0 ) as t1 ON t1.ean = products.ean
INNER JOIN (SELECT ean, count(*) as tc2
                    FROM keywords
                    WHERE ( keyword like 'ip%' )
                    GROUP BY ean
                    HAVING tc2 > 0 ) as t2 ON t2.ean = products.ean
INNER JOIN (SELECT ean, count(*) as tc3
                    FROM keywords
                    WHERE ( keyword like 'hea%' )
                    GROUP BY ean
                    HAVING tc3 > 0  ) as t3 ON t3.ean = products.ean
ORDER BY products.ean
```

答:
Perhaps you're after something more like this...

```<code>SELECT p.ean
     , p.description
  FROM products p
  JOIN keywords k
    ON k.ean = p.ean
 WHERE k.keyword LIKE 'iP%'
    OR k.keyword LIKE 'hea%'
    OR k.keyword LIKE 'gen%'
 GROUP
    BY p.ean
HAVING COUNT(DISTINCT CASE WHEN k.keyword LIKE 'iP%' THEN 'iP'
                           WHEN k.keyword LIKE 'hea%' THEN 'hea'
                           WHEN k.keyword LIKE 'gen%' THEN 'gen'
                           ELSE keyword END) = 3;
</code>```

http://sqlfiddle.com/#!9/270f9/25

Body:
I have a table of keywords (ID,ean,keyword) and another table with product details. I want the search to return EANs where all keywords match at least once, however the closest I have got is the following, but this returns matches that have the first term in them 3 times for example.

To give an example, let's say I have a product called 'Generic headphones - iPhone, iPad, iPod' and I searched 'gen%' 'hea%' 'ip%' it would come back as a match, but it would also match 'Apple headphones - iPhone, iPad, iPod' due to the 3 ip words, which is not desired.

SQL Fiddle
I want EAN 1 to match only, so matches need to be at least 1 for each term.

Any help would be much appreciated.

SELECT     Count(keywords.ean) AS cc,
           products.*
FROM       keywords
INNER JOIN products
ON         products.ean = keywords.ean
WHERE      (
                      keyword LIKE 'gen%'
                                 || keyword like 'ip%'
                                 || keyword LIKE 'hea%')
GROUP BY   (keywords.ean)
HAVING     cc>=3
ORDER BY   `products`.`ean` ASC

UPDATE: This gets the desired results, but there must be more efficient ways to do this.

SELECT products.*
FROM products
INNER JOIN (SELECT ean, count(*) as tc1
                    FROM keywords
                    WHERE ( keyword like 'gen%' )
                    GROUP BY ean
                    HAVING tc1 > 0 ) as t1 ON t1.ean = products.ean
INNER JOIN (SELECT ean, count(*) as tc2
                    FROM keywords
                    WHERE ( keyword like 'ip%' )
                    GROUP BY ean
                    HAVING tc2 > 0 ) as t2 ON t2.ean = products.ean
INNER JOIN (SELECT ean, count(*) as tc3
                    FROM keywords
                    WHERE ( keyword like 'hea%' )
                    GROUP BY ean
                    HAVING tc3 > 0  ) as t3 ON t3.ean = products.ean
ORDER BY products.ean

Body:
Perhaps you're after something more like this...

SELECT p.ean
     , p.description
  FROM products p
  JOIN keywords k
    ON k.ean = p.ean
 WHERE k.keyword LIKE 'iP%'
    OR k.keyword LIKE 'hea%'
    OR k.keyword LIKE 'gen%'
 GROUP
    BY p.ean
HAVING COUNT(DISTINCT CASE WHEN k.keyword LIKE 'iP%' THEN 'iP'
                           WHEN k.keyword LIKE 'hea%' THEN 'hea'
                           WHEN k.keyword LIKE 'gen%' THEN 'gen'
                           ELSE keyword END) = 3;

http://sqlfiddle.com/#!9/270f9/25


问:
I wanted to add an element to my array after sorting the array
Here is my code</p>

```<code>import java.util.*;

public class ArrayExample {
    public static void main(String[] args) {
        Integer arr[] = {5,4,3,2,15,8,9};
        List<Integer> list = Arrays.asList(arr);
        Collections.sort(list);
        System.out.println(list);
        list.add(6);// here I am adding 6 to my array.
        System.out.println(list);
        // Here I should get output as [2,3,4,5,6,8,9,15]
    }
}
</code>```

答:
You can add an element without using a list by using 2 arrays: a source array src and a destination array dest. The destination array will have one more element than the source one. You simply need to copy all the elements of the source array to the destination, and add your new element. Depends on different requirement of your post title & your post body, I added 2 solutions:

Solution 1

This solution add an element to your array AFTER sorting the array, as mentioned in the post title. But please notice that the element added is located at the tail of the new array.

```<code>Integer src[] = { 5, 4, 3, 2, 15, 8, 9 };
Integer dest[] = new Integer[src.length + 1];
Arrays.sort(src);
System.out.println(Arrays.toString(src));
// [2, 3, 4, 5, 8, 9, 15]

System.arraycopy(src, 0, dest, 0, src.length);
dest[src.length] = 6;
System.out.println(Arrays.toString(dest));
// [2, 3, 4, 5, 8, 9, 15, 6]
//                        ^
</code>```

Solution 2

This solution add an element to your array BEFORE sorting the array. It contains the expected array as mentioned in your code comment in the post body.

```<code>Integer src[] = { 5, 4, 3, 2, 15, 8, 9 };
Integer dest[] = new Integer[src.length + 1];

System.arraycopy(src, 0, dest, 0, src.length);
dest[src.length] = 6;
Arrays.sort(dest);

System.out.println(Arrays.toString(dest));
// [2, 3, 4, 5, 6, 8, 9, 15]
//              ^
</code>```

See also:

Sorting methods in Arrays (Java Platform SE 8) - Oracle Help Center

System#arraycopy(Object, int, Object, int, int)

Body:
Here is my code

import java.util.*;

public class ArrayExample {
    public static void main(String[] args) {
        Integer arr[] = {5,4,3,2,15,8,9};
        List<Integer> list = Arrays.asList(arr);
        Collections.sort(list);
        System.out.println(list);
        list.add(6);// here I am adding 6 to my array.
        System.out.println(list);
        // Here I should get output as [2,3,4,5,6,8,9,15]
    }
}

Body:
You can add an element without using a list by using 2 arrays: a source array src and a destination array dest. The destination array will have one more element than the source one. You simply need to copy all the elements of the source array to the destination, and add your new element. Depends on different requirement of your post title & your post body, I added 2 solutions:

Solution 1

This solution add an element to your array AFTER sorting the array, as mentioned in the post title. But please notice that the element added is located at the tail of the new array.

Integer src[] = { 5, 4, 3, 2, 15, 8, 9 };
Integer dest[] = new Integer[src.length + 1];
Arrays.sort(src);
System.out.println(Arrays.toString(src));
// [2, 3, 4, 5, 8, 9, 15]

System.arraycopy(src, 0, dest, 0, src.length);
dest[src.length] = 6;
System.out.println(Arrays.toString(dest));
// [2, 3, 4, 5, 8, 9, 15, 6]
//                        ^

Solution 2

This solution add an element to your array BEFORE sorting the array. It contains the expected array as mentioned in your code comment in the post body.

Integer src[] = { 5, 4, 3, 2, 15, 8, 9 };
Integer dest[] = new Integer[src.length + 1];

System.arraycopy(src, 0, dest, 0, src.length);
dest[src.length] = 6;
Arrays.sort(dest);

System.out.println(Arrays.toString(dest));
// [2, 3, 4, 5, 6, 8, 9, 15]
//              ^

See also:

Sorting methods in Arrays (Java Platform SE 8) - Oracle Help Center

System#arraycopy(Object, int, Object, int, int)


答:
var greetdate=new Date()
var hours=greetdate.getHours()

if (hours>=5&&hours<=11)
//MESSAGE FOR MORNING
document.write('
Hello! Good Morning! Have a nice day.
')
else if (hours==12)
//MESSAGE FOR NOON
document.write('
Good Noon Visitor!
')
else if (hours>=13&&hours<=17)
//MESSAGE FOR AFTERNOON
document.write('
Good Afternoon!
')
else if (hours>=18&&hours<=20)
//MESSAGE FOR EVENING (6pm-8pm)
document.write('
Good Evening!
')
else if (hours>=21&&hours<=11)
//MESSAGE FOR NIGHT (9pm-11pm)
document.write('
Good Night!
')
else
//MESSAGE FOR LATE NIGHT (12pm-4am)
document.write('
Wow! You`re still awake. Working Late?
')```

Title: Showing Greeting Message in Javascript

Body:
var greetdate=new Date()
var hours=greetdate.getHours()

if (hours>=5&&hours<=11)
//MESSAGE FOR MORNING
document.write('<h2>Hello! Good Morning! Have a nice day.</h2>')
else if (hours==12)
//MESSAGE FOR NOON
document.write('<h2>Good Noon Visitor! </h2>')
else if (hours>=13&&hours<=17)
//MESSAGE FOR AFTERNOON
document.write('<h2>Good Afternoon! </h2>')
else if (hours>=18&&hours<=20)
//MESSAGE FOR EVENING (6pm-8pm)
document.write('<h2>Good Evening! </h2>')
else if (hours>=21&&hours<=11)
//MESSAGE FOR NIGHT (9pm-11pm)
document.write('<h2>Good Night! </h2>')
else
//MESSAGE FOR LATE NIGHT (12pm-4am)
document.write('<h2>Wow! You`re still awake. Working Late?</h2>')


问:
Play a 2nd flash video after the first ends
I have a flash object set up in the standard format:

```<code><script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript">
swfobject.embedSWF("swfplayer.swf", "myContent", "300", "120", "9", "expressInstall.swf");
</script>
</code>```

but I want to start playing a second flash video on a different part of the web page the moment the first video ends. Is there a kind of listener of some sort to use?

Thanks

答:
You could approach it from these two possibilities:  LocalConnection or ExternalInterface.

I would go with ExternalInterface personally.  With it, you can set up a javascript function that receives a call from videoPlayer_1 when its video has ended.  To this javascript function you could pass an ID to determine which player has finished, and then send a call back up to the appropriate next player to tell it to start playing.  You could repeat this process as many times as you have/swf's with videos.

I would have included an example but you didn't mention as2 or 3.

As for LocalConnection, you could create a group of movies with a local data connection, but this is easily broken by certain scenarios of multiple browsers/swfs, so probably not the most reliable method.  However if you wanted to give it a shot, look up Grant Skinner's SwfBridge class to make  things much easier.

Body:
I have a flash object set up in the standard format:

but I want to start playing a second flash video on a different part of the web page the moment the first video ends. Is there a kind of listener of some sort to use?

Thanks


问:
How to select text between the specific occurrences of particular characters
How can I select text between the specific occurrences of particular characters?

For example in below string:

Lorem|Ipsum|is|simply|dummy|text|A123|the|printing|and|typesetting|industry|

I want to remove/replace text between the 6th and 7th occurrence of '|' character, i.e. the word 'A123'.

Is it possible to do so with Regex?

答:
You didn't specify POSIX, PCRE or some other regex, but I'll assume PCRE. While regex doesn't let you select 'Nth occurrence of a character', you can always select Nth occurrence of a group if there is some pattern.

In your case, since pipe is a separator you can always select a group of any character followed by a pipe, and then select that group 6 times, then select anything until the next pipe to actually get your characters. Since you seem to be the most active in PHP, here's a PHP approach:

```<code>$data = "Lorem|Ipsum|is|simply|dummy|text|A123|the|printing|and|typesetting|industry|";
$foo_data = preg_replace('/^((.*?\|){6})[^|]+/', '$1FOO', $data);
echo $foo_data;  // Lorem|Ipsum|is|FOO|dummy|text|A123|the|printing|and|typesetting|industry|
</code>```

You can remove the leading caret if you want to replace every seventh occurrence. You can also add brackets around the second part ([^|]+) if you need to manipulate/extract it.

Body:
You didn't specify POSIX, PCRE or some other regex, but I'll assume PCRE. While regex doesn't let you select 'Nth occurrence of a character', you can always select Nth occurrence of a group if there is some pattern.

In your case, since pipe is a separator you can always select a group of any character followed by a pipe, and then select that group 6 times, then select anything until the next pipe to actually get your characters. Since you seem to be the most active in PHP, here's a PHP approach:

$data = "Lorem|Ipsum|is|simply|dummy|text|A123|the|printing|and|typesetting|industry|";
$foo_data = preg_replace('/^((.*?\|){6})[^|]+/', '$1FOO', $data);
echo $foo_data;  // Lorem|Ipsum|is|FOO|dummy|text|A123|the|printing|and|typesetting|industry|

You can remove the leading caret if you want to replace every seventh occurrence. You can also add brackets around the second part ([^|]+) if you need to manipulate/extract it.


问:
How does comparison of a slice with an array work in Rust?
Why would [1,1] == &[1,1] not even compile (presumably because they're different types), yet the following snippet compiles and runs fine.

```<code>let a: [i32; 100] = [1; 100];
let b: &[i32] = &a[1..3];
if b == [1, 1] { // comparison with &[1, 1] works as well
    println!("it works"); // this does get printed
}
</code>```

答:
Right now, arrays in Rust are somewhat special because Rust lacks type-level integers. You can't write a function fn f<T, N>(array: &[T; N]). Likewise, you can't implement a trait which is generic over N.

The standard library provides some trait implementations for array lengths ranging from 0 to 32 to mitigate this issue, which is why b == [1,1] works. There's an implementation of the trait PartialEq for this case:

```<code>impl<'a, 'b, A, B> PartialEq<[A; 2]> for &'b [B]
where B: PartialEq<A>
</code>```

However, the trait PartialEq<&[A; 2]> is not implemented for [B; 2]. Thus you cannot compare [1, 1] and &[1, 1]. b == [1; 33] will not work in your example too, as there's no implementations for arrays longer than 32 elements.

But there's ongoing effort to bring type-level integers into Rust. RFC 2000 is the latest proposal.

For the time being  you can rely on implicit conversion from reference to the array to reference to slice. Like this

```<code>fn f<T>(slice: &[T]) {}

f(&[1, 2, 3, 4]);
</code>```

Body:
Why would [1,1] == &[1,1] not even compile (presumably because they're different types), yet the following snippet compiles and runs fine.

let a: [i32; 100] = [1; 100];
let b: &[i32] = &a[1..3];
if b == [1, 1] { // comparison with &[1, 1] works as well
    println!("it works"); // this does get printed
}

Body:
Right now, arrays in Rust are somewhat special because Rust lacks type-level integers. You can't write a function fn f<T, N>(array: &[T; N]). Likewise, you can't implement a trait which is generic over N.

The standard library provides some trait implementations for array lengths ranging from 0 to 32 to mitigate this issue, which is why b == [1,1] works. There's an implementation of the trait PartialEq for this case:

impl<'a, 'b, A, B> PartialEq<[A; 2]> for &'b [B]
where B: PartialEq<A>

However, the trait PartialEq<&[A; 2]> is not implemented for [B; 2]. Thus you cannot compare [1, 1] and &[1, 1]. b == [1; 33] will not work in your example too, as there's no implementations for arrays longer than 32 elements.

But there's ongoing effort to bring type-level integers into Rust. RFC 2000 is the latest proposal.

For the time being  you can rely on implicit conversion from reference to the array to reference to slice. Like this

fn f<T>(slice: &[T]) {}

f(&[1, 2, 3, 4]);


问:
How to change the color of legend in chartjs and be able to add one more legend?
I want to change the color of legend, because I want different colors to represent different situations.But now the legend uses just the first color I set on the bar chart.

I also want to ask, is it able to set one more legend?Like pink is for situationA, blue for B?

```<code>Here is the link:
</code>```

Code is here
Can anyone help?Thank you so much.

答:
To set more legends, you need to add multiple datasets. Each dataset will represent one legend and the legend's color will automatically be set according to the dataset's background color.

Chart.plugins.register({
   beforeDraw: function(c) {
      var legends = c.legend.legendItems;
      legends.forEach(function(e) {
         e.fillStyle = '#07C';
      });
   }
});

var canvas = document.getElementById('myChart');

var data = {
   labels: ["January", "February", "March", "April", "May", "June"],
   datasets: [{
      label: "My First dataset",
      backgroundColor: "rgba(255,99,132,0.4)",
      hoverBorderColor: "rgba(255,99,132,1)",
      data: [65, 59, 20, 81, 56, 55],
   }, {
      label: "My Second dataset",
      backgroundColor: "rgba(25,25,255,0.4)",
      hoverBorderColor: "rgba(255,99,132,1)",
      data: [65, 59, 20, 81, 56, 55],
   }]
};

var option = {
   scales: {
      xAxes: [{
         stacked: true
      }],
      yAxes: [{
         stacked: true,
         gridLines: {
            display: true,
            color: "rgba(255,99,132,0.2)"
         }
      }]
   }
};

var myBarChart = Chart.Bar(canvas, {
   data: data,
   options: option
});```
<pre class="snippet-code-html lang-html prettyprint-override"><code><script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<canvas id="myChart" width="400" height="200"></canvas></code>```

Body:
I want to change the color of legend, because I want different colors to represent different situations.But now the legend uses just the first color I set on the bar chart.

I also want to ask, is it able to set one more legend?Like pink is for situationA, blue for B?

Here is the link:

Code is here
Can anyone help?Thank you so much.

Body:
To set more legends, you need to add multiple datasets. Each dataset will represent one legend and the legend's color will automatically be set according to the dataset's background color.

Chart.plugins.register({
   beforeDraw: function(c) {
      var legends = c.legend.legendItems;
      legends.forEach(function(e) {
         e.fillStyle = '#07C';
      });
   }
});

var canvas = document.getElementById('myChart');

var data = {
   labels: ["January", "February", "March", "April", "May", "June"],
   datasets: [{
      label: "My First dataset",
      backgroundColor: "rgba(255,99,132,0.4)",
      hoverBorderColor: "rgba(255,99,132,1)",
      data: [65, 59, 20, 81, 56, 55],
   }, {
      label: "My Second dataset",
      backgroundColor: "rgba(25,25,255,0.4)",
      hoverBorderColor: "rgba(255,99,132,1)",
      data: [65, 59, 20, 81, 56, 55],
   }]
};

var option = {
   scales: {
      xAxes: [{
         stacked: true
      }],
      yAxes: [{
         stacked: true,
         gridLines: {
            display: true,
            color: "rgba(255,99,132,0.2)"
         }
      }]
   }
};

var myBarChart = Chart.Bar(canvas, {
   data: data,
   options: option
});

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<canvas id="myChart" width="400" height="200"></canvas>


问:
super() in a constructor of a class without inheritance
The following code (shortened version of the class) I have seen in a Java Video-Tutorial.

```<code>public class Address {
    private String firstName;
    private String lastName;

    public Address() {
        super();
    }

    public Address(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    ...
}
</code>```

The class which is shown there has no extend keyword. Nevertheless super() is used within the constructor without a parameter.

It calls the constructor of Object class? Am I right?

But why?

What is the reason for having this call of super()?

答:
that is what you get when you let your IDE to autogenerate the Constructors of your class.. since that class is not extending anything then calling super is the same as calling the constructor of the object class, which is actually taking no effects on the Address class implementation

so in your case

```<code>public Address() {
    super();
}
</code>```

is the same as

```<code>public Address() {

}
</code>```

Body:
The following code (shortened version of the class) I have seen in a Java Video-Tutorial.

public class Address {
    private String firstName;
    private String lastName;

    public Address() {
        super();
    }

    public Address(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    ...
}

The class which is shown there has no extend keyword. Nevertheless super() is used within the constructor without a parameter.

It calls the constructor of Object class? Am I right?

But why?

What is the reason for having this call of super()?

Body:
that is what you get when you let your IDE to autogenerate the Constructors of your class.. since that class is not extending anything then calling super is the same as calling the constructor of the object class, which is actually taking no effects on the Address class implementation

so in your case

public Address() {
    super();
}

is the same as

public Address() {

}


问:
How does NSFetchedResultsControllerDelegate work?
I'm new with iOS (Swift) and trying to understand NSFetchedResultsControllerDelegate mechanism.
What I specifically don't understand is how does NSFetchedResultsChangeType is recognized. What invokes insert/delete/update etc. actions?
When "func controller(...)" functions are called?
I can't get it from Apple's documentation.
Please shed some light.</p>

答: NSFetchedResultsController is not that smart. When you create it, you set a fetchedRequest and a context on it, and tell it to performFetch.  Once it has performed a fetch it has an array of objects that matches the predicate.  It then monitors all changes to the core data context that was passed to it.  When an object (of the same Entity type) is changed the fetchedResultsController then runs the predicate of the fetch request on the change object to decide if it should be added or removed from the list. If the object was deleted, or was in the list before, and is now not in the list then it is a delete.  If it was not in the list before but now it does pass the predicate then it is an insert.  If one of the fields that are used by the sort descriptor is changed then it is a move, otherwise it is an update. If many changes are done at the same time (one save on a context) the events will be delegated in the order - delete, insert, move, update.  The value of indexPath is the index before any inserts or deletes, and newIndexPath is the value after any inserts or deletes.  Does that answer your question?


问:
Node.js console.log() not logging anything
Trying out node.js for the first time. Set up node, set up the example app from the nodejs.org site. Can start the server fine, but console.log() isn't actually logging anything. Tried the Javascript console in Chrome, Firefox, and Safari - nothing appears in the log. Also checked Console on my Mac just for kicks, nothing was there either. What am I missing?

(Here's the example code that works but doesn't log anything.)

```<code>var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/');
</code>```

答:
Using modern --inspect with node the console.log is captured and relayed to the browser.

node --inspect myApp.js

or to capture early logging --inspect-brk can be used to stop the program on the first line of the first module...

node --inspect-brk myApp.js

Body:
Trying out node.js for the first time. Set up node, set up the example app from the nodejs.org site. Can start the server fine, but console.log() isn't actually logging anything. Tried the Javascript console in Chrome, Firefox, and Safari - nothing appears in the log. Also checked Console on my Mac just for kicks, nothing was there either. What am I missing?

(Here's the example code that works but doesn't log anything.)

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/');


问:
Using regex for the first time
I just started using regex and I'm trying to solve this problem, but it keeps return null. What is wrong with my code?
I want it to return this = (833) 741-2093</p>

```<code>function phoneNumber(numbers){
  var num = numbers.join('');
  var r = /\(\d{3}\)\s\d{3}\-\d{4}/;
  var match = num.match(r);
  return match;
}

var output = phoneNumber([8, 3, 3, 7, 4, 1, 2, 0, 9, 3]);

console.log(output);
</code>```

答:
Here you go…

function phoneNumber(numbers){
  var num = numbers.join('');
  var r = /^(\d{3})(\d{3})(\d{4})$/;
  return num.replace(r,'($1) $2-$3');
}

var output = phoneNumber([8, 3, 3, 7, 4, 1, 2, 0, 9, 3]);

console.log(output);```

Title: Using regex for the first time

Body:
I just started using regex and I'm trying to solve this problem, but it keeps return null. What is wrong with my code?
I want it to return this = (833) 741-2093

function phoneNumber(numbers){
  var num = numbers.join('');
  var r = /\(\d{3}\)\s\d{3}\-\d{4}/;
  var match = num.match(r);
  return match;
}

var output = phoneNumber([8, 3, 3, 7, 4, 1, 2, 0, 9, 3]);

console.log(output);